xref: /AOO41X/main/sal/osl/w32/thread.c (revision 647f063d49501903f1667b75f5634541fc603283)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "system.h"
25 
26 #include <osl/diagnose.h>
27 #include <osl/thread.h>
28 #include <rtl/alloc.h>
29 #include <osl/time.h>
30 #include <osl/interlck.h>
31 #include <rtl/tencinfo.h>
32 
33 /*
34     Thread-data structure hidden behind oslThread:
35 */
36 typedef struct _osl_TThreadImpl
37 {
38     HANDLE              m_hThread;      /* OS-handle used for all thread-functions */
39     unsigned            m_ThreadId;     /* identifier for this thread */
40     sal_Int32           m_nTerminationRequested;
41     oslWorkerFunction   m_WorkerFunction;
42     void*               m_pData;
43 
44 } osl_TThreadImpl;
45 
46 #define THREADIMPL_FLAGS_TERMINATE  0x0001
47 
48 static unsigned __stdcall oslWorkerWrapperFunction(void* pData);
49 static oslThread oslCreateThread(oslWorkerFunction pWorker, void* pThreadData, sal_uInt32 nFlags);
50 
51 /*****************************************************************************/
52 /* oslWorkerWrapperFunction */
53 /*****************************************************************************/
oslWorkerWrapperFunction(void * pData)54 static unsigned __stdcall oslWorkerWrapperFunction(void* pData)
55 {
56     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)pData;
57 
58     /* Initialize COM */
59 
60     CoInitializeEx(NULL, COINIT_MULTITHREADED);
61 
62     /* call worker-function with data */
63 
64     pThreadImpl->m_WorkerFunction(pThreadImpl->m_pData);
65 
66     CoUninitialize();
67 
68     return (0);
69 }
70 
71 /*****************************************************************************/
72 /* oslCreateThread */
73 /*****************************************************************************/
oslCreateThread(oslWorkerFunction pWorker,void * pThreadData,sal_uInt32 nFlags)74 static oslThread oslCreateThread(oslWorkerFunction pWorker,
75                                  void* pThreadData,
76                                  sal_uInt32 nFlags)
77 {
78     osl_TThreadImpl* pThreadImpl;
79 
80     /* alloc mem. for our internal data structure */
81     pThreadImpl= malloc(sizeof(osl_TThreadImpl));
82 
83     OSL_ASSERT(pThreadImpl);
84 
85     if ( pThreadImpl == 0 )
86     {
87         return 0;
88     }
89 
90     pThreadImpl->m_WorkerFunction= pWorker;
91     pThreadImpl->m_pData= pThreadData;
92     pThreadImpl->m_nTerminationRequested= 0;
93 
94     pThreadImpl->m_hThread=
95         (HANDLE)_beginthreadex(NULL,                        /* no security */
96                                0,                           /* default stack-size */
97                                oslWorkerWrapperFunction,    /* worker-function */
98                                pThreadImpl,                 /* provide worker-function with data */
99                                nFlags,                      /* start thread immediately or suspended */
100                                &pThreadImpl->m_ThreadId);
101 
102     if(pThreadImpl->m_hThread == 0)
103     {
104         /* create failed */
105         free(pThreadImpl);
106         return 0;
107     }
108 
109     return (oslThread)pThreadImpl;
110 }
111 
112 /*****************************************************************************/
113 /* osl_createThread */
114 /*****************************************************************************/
osl_createThread(oslWorkerFunction pWorker,void * pThreadData)115 oslThread SAL_CALL osl_createThread(oslWorkerFunction pWorker,
116                                     void* pThreadData)
117 {
118     return oslCreateThread(pWorker, pThreadData, 0);
119 }
120 
121 /*****************************************************************************/
122 /* osl_createSuspendedThread */
123 /*****************************************************************************/
osl_createSuspendedThread(oslWorkerFunction pWorker,void * pThreadData)124 oslThread SAL_CALL osl_createSuspendedThread(oslWorkerFunction pWorker,
125                                              void* pThreadData)
126 {
127     return oslCreateThread(pWorker, pThreadData, CREATE_SUSPENDED);
128 }
129 
130 /*****************************************************************************/
131 /* osl_getThreadIdentifier */
132 /*****************************************************************************/
osl_getThreadIdentifier(oslThread Thread)133 oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread)
134 {
135     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
136 
137     if (pThreadImpl != NULL)
138         return ((oslThreadIdentifier)pThreadImpl->m_ThreadId);
139     else
140         return ((oslThreadIdentifier)GetCurrentThreadId());
141 }
142 
143 /*****************************************************************************/
144 /* osl_destroyThread */
145 /*****************************************************************************/
osl_destroyThread(oslThread Thread)146 void SAL_CALL osl_destroyThread(oslThread Thread)
147 {
148     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
149 
150     if (Thread == 0) /* valid ptr? */
151     {
152         /* thread already destroyed or not created */
153         return;
154     }
155 
156     /* !!!! _exitthreadex does _not_ call CloseHandle !!! */
157     CloseHandle( pThreadImpl->m_hThread );
158 
159     /* free memory */
160     free(Thread);
161 }
162 
163 /*****************************************************************************/
164 /* osl_resumeThread */
165 /*****************************************************************************/
osl_resumeThread(oslThread Thread)166 void SAL_CALL osl_resumeThread(oslThread Thread)
167 {
168     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
169 
170     OSL_ASSERT(pThreadImpl);        /* valid ptr? */
171 
172     ResumeThread(pThreadImpl->m_hThread);
173 }
174 
175 /*****************************************************************************/
176 /* osl_suspendThread */
177 /*****************************************************************************/
osl_suspendThread(oslThread Thread)178 void SAL_CALL osl_suspendThread(oslThread Thread)
179 {
180     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
181 
182     OSL_ASSERT(pThreadImpl);        /* valid ptr? */
183 
184     SuspendThread(pThreadImpl->m_hThread);
185 }
186 
187 /*****************************************************************************/
188 /* osl_setThreadPriority */
189 /*****************************************************************************/
osl_setThreadPriority(oslThread Thread,oslThreadPriority Priority)190 void SAL_CALL osl_setThreadPriority(oslThread Thread,
191                            oslThreadPriority Priority)
192 {
193     int winPriority;
194     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
195 
196     OSL_ASSERT(pThreadImpl);        /* valid ptr? */
197 
198 
199     /*  map enum to WIN32 levels
200         it would be faster and more elegant to preset
201         the enums, but that would require an #ifdef in
202         the exported header, which is not desired.
203     */
204     switch(Priority) {
205 
206     case osl_Thread_PriorityHighest:
207         winPriority= THREAD_PRIORITY_HIGHEST;
208         break;
209 
210     case osl_Thread_PriorityAboveNormal:
211         winPriority= THREAD_PRIORITY_ABOVE_NORMAL;
212         break;
213 
214     case osl_Thread_PriorityNormal:
215         winPriority= THREAD_PRIORITY_NORMAL;
216         break;
217 
218     case osl_Thread_PriorityBelowNormal:
219         winPriority= THREAD_PRIORITY_BELOW_NORMAL;
220         break;
221 
222     case osl_Thread_PriorityLowest:
223         winPriority= THREAD_PRIORITY_LOWEST;
224         break;
225 
226     case osl_Thread_PriorityUnknown:
227         OSL_ASSERT(FALSE);      /* only fools try this...*/
228 
229         /* let release-version behave friendly */
230         return;
231 
232     default:
233         OSL_ASSERT(FALSE);      /* enum expanded, but forgotten here...*/
234 
235         /* let release-version behave friendly */
236         return;
237     }
238 
239     SetThreadPriority(pThreadImpl->m_hThread, winPriority);
240 }
241 
242 /*****************************************************************************/
243 /* osl_getThreadPriority  */
244 /*****************************************************************************/
osl_getThreadPriority(const oslThread Thread)245 oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread)
246 {
247     int winPriority;
248     oslThreadPriority Priority;
249 
250     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
251 
252     /* invalid arguments ?*/
253     if(pThreadImpl==0 || pThreadImpl->m_hThread==0)
254     {
255         return osl_Thread_PriorityUnknown;
256     }
257 
258     winPriority=
259         GetThreadPriority(pThreadImpl->m_hThread);
260 
261 
262     if(winPriority == THREAD_PRIORITY_ERROR_RETURN)
263     {
264         return osl_Thread_PriorityUnknown;
265     }
266 
267     /* map WIN32 priority to enum */
268     switch(winPriority)
269     {
270     case THREAD_PRIORITY_TIME_CRITICAL:
271     case THREAD_PRIORITY_HIGHEST:
272         Priority= osl_Thread_PriorityHighest;
273         break;
274 
275     case THREAD_PRIORITY_ABOVE_NORMAL:
276         Priority= osl_Thread_PriorityAboveNormal;
277         break;
278 
279     case THREAD_PRIORITY_NORMAL:
280         Priority= osl_Thread_PriorityNormal;
281         break;
282 
283     case THREAD_PRIORITY_BELOW_NORMAL:
284         Priority= osl_Thread_PriorityBelowNormal;
285         break;
286 
287     case THREAD_PRIORITY_IDLE:
288     case THREAD_PRIORITY_LOWEST:
289         Priority= osl_Thread_PriorityLowest;
290         break;
291 
292     default:
293         OSL_ASSERT(FALSE);      /* WIN32 API changed, incorporate new prio-level! */
294 
295         /* release-version behaves friendly */
296         Priority= osl_Thread_PriorityUnknown;
297     }
298 
299     return Priority;
300 }
301 
302 /*****************************************************************************/
303 /* osl_isThreadRunning */
304 /*****************************************************************************/
osl_isThreadRunning(const oslThread Thread)305 sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
306 {
307     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
308 
309     /* invalid arguments ?*/
310     if(pThreadImpl==0 || pThreadImpl->m_hThread==0)
311     {
312         return sal_False;
313     }
314 
315     return (sal_Bool)(WaitForSingleObject(pThreadImpl->m_hThread, 0) != WAIT_OBJECT_0);
316 }
317 
318 /*****************************************************************************/
319 /* osl_joinWithThread */
320 /*****************************************************************************/
osl_joinWithThread(oslThread Thread)321 void SAL_CALL osl_joinWithThread(oslThread Thread)
322 {
323     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
324 
325     /* invalid arguments?*/
326     if(pThreadImpl==0 || pThreadImpl->m_hThread==0)
327     {
328         /* assume thread is not running */
329         return;
330     }
331 
332     WaitForSingleObject(pThreadImpl->m_hThread, INFINITE);
333 }
334 
335 /*****************************************************************************/
336 /* osl_waitThread */
337 /*****************************************************************************/
osl_waitThread(const TimeValue * pDelay)338 void SAL_CALL osl_waitThread(const TimeValue* pDelay)
339 {
340     if (pDelay)
341     {
342         DWORD millisecs = pDelay->Seconds * 1000L + pDelay->Nanosec / 1000000L;
343 
344         Sleep(millisecs);
345     }
346 }
347 
348 /*****************************************************************************/
349 /* osl_terminateThread */
350 /*****************************************************************************/
osl_terminateThread(oslThread Thread)351 void SAL_CALL osl_terminateThread(oslThread Thread)
352 {
353     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
354 
355     /* invalid arguments?*/
356     if (pThreadImpl==0 || pThreadImpl->m_hThread==0)
357     {
358         /* assume thread is not running */
359         return;
360     }
361 
362     osl_incrementInterlockedCount(&(pThreadImpl->m_nTerminationRequested));
363 }
364 
365 
366 /*****************************************************************************/
367 /* osl_scheduleThread */
368 /*****************************************************************************/
osl_scheduleThread(oslThread Thread)369 sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread)
370 {
371     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
372 
373     osl_yieldThread();
374 
375     /* invalid arguments?*/
376     if (pThreadImpl==0 || pThreadImpl->m_hThread==0)
377     {
378         /* assume thread is not running */
379         return sal_False;
380     }
381 
382     return (sal_Bool)(0 == pThreadImpl->m_nTerminationRequested);
383 }
384 
385 /*****************************************************************************/
386 /* osl_yieldThread */
387 /*****************************************************************************/
osl_yieldThread(void)388 void SAL_CALL osl_yieldThread(void)
389 {
390     Sleep(0);
391 }
392 
osl_setThreadName(char const * name)393 void SAL_CALL osl_setThreadName(char const * name) {
394 #ifdef _MSC_VER
395     /* See <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>: */
396 #pragma pack(push, 8)
397     struct {
398         DWORD dwType;
399         LPCSTR szName;
400         DWORD dwThreadID;
401         DWORD dwFlags;
402     } info;
403 #pragma pack(pop)
404     info.dwType = 0x1000;
405     info.szName = name;
406     info.dwThreadID = (DWORD) -1;
407     info.dwFlags = 0;
408     __try {
409         RaiseException(
410             0x406D1388, 0, sizeof info / sizeof (ULONG_PTR),
411             (ULONG_PTR *) &info);
412     } __except (EXCEPTION_EXECUTE_HANDLER) {}
413 #else
414     (void) name;
415 #endif
416 }
417 
418 typedef struct _TLS
419 {
420     DWORD                           dwIndex;
421     oslThreadKeyCallbackFunction    pfnCallback;
422     struct _TLS                     *pNext, *pPrev;
423 } TLS, *PTLS;
424 
425 static  PTLS        g_pThreadKeyList = NULL;
426 CRITICAL_SECTION    g_ThreadKeyListCS;
427 
AddKeyToList(PTLS pTls)428 static void AddKeyToList( PTLS pTls )
429 {
430     if ( pTls )
431     {
432         EnterCriticalSection( &g_ThreadKeyListCS );
433 
434         pTls->pNext = g_pThreadKeyList;
435         pTls->pPrev = 0;
436 
437         if ( g_pThreadKeyList )
438             g_pThreadKeyList->pPrev = pTls;
439 
440         g_pThreadKeyList = pTls;
441 
442         LeaveCriticalSection( &g_ThreadKeyListCS );
443     }
444 }
445 
RemoveKeyFromList(PTLS pTls)446 static void RemoveKeyFromList( PTLS pTls )
447 {
448     if ( pTls )
449     {
450         EnterCriticalSection( &g_ThreadKeyListCS );
451         if ( pTls->pPrev )
452             pTls->pPrev->pNext = pTls->pNext;
453         else
454         {
455             OSL_ASSERT( pTls == g_pThreadKeyList );
456             g_pThreadKeyList = pTls->pNext;
457         }
458 
459         if ( pTls->pNext )
460             pTls->pNext->pPrev = pTls->pPrev;
461         LeaveCriticalSection( &g_ThreadKeyListCS );
462     }
463 }
464 
_osl_callThreadKeyCallbackOnThreadDetach(void)465 void SAL_CALL _osl_callThreadKeyCallbackOnThreadDetach(void)
466 {
467     PTLS    pTls;
468 
469 
470     EnterCriticalSection( &g_ThreadKeyListCS );
471     pTls = g_pThreadKeyList;
472     while ( pTls )
473     {
474         if ( pTls->pfnCallback )
475         {
476             void    *pValue = TlsGetValue( pTls->dwIndex );
477 
478             if ( pValue )
479                 pTls->pfnCallback( pValue );
480         }
481 
482         pTls = pTls->pNext;
483     }
484     LeaveCriticalSection( &g_ThreadKeyListCS );
485 }
486 
487 /*****************************************************************************/
488 /* osl_createThreadKey */
489 /*****************************************************************************/
osl_createThreadKey(oslThreadKeyCallbackFunction pCallback)490 oslThreadKey SAL_CALL osl_createThreadKey(oslThreadKeyCallbackFunction pCallback)
491 {
492     PTLS    pTls = rtl_allocateMemory( sizeof(TLS) );
493 
494     if ( pTls )
495     {
496         pTls->pfnCallback = pCallback;
497         if ( (DWORD)-1 == (pTls->dwIndex = TlsAlloc()) )
498         {
499             rtl_freeMemory( pTls );
500             pTls = 0;
501         }
502         else
503             AddKeyToList( pTls );
504     }
505 
506     return ((oslThreadKey)pTls);
507 }
508 
509 /*****************************************************************************/
510 /* osl_destroyThreadKey */
511 /*****************************************************************************/
osl_destroyThreadKey(oslThreadKey Key)512 void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
513 {
514     if (Key != 0)
515     {
516         PTLS    pTls = (PTLS)Key;
517 
518         RemoveKeyFromList( pTls );
519         TlsFree( pTls->dwIndex );
520         rtl_freeMemory( pTls );
521     }
522 }
523 
524 /*****************************************************************************/
525 /* osl_getThreadKeyData */
526 /*****************************************************************************/
osl_getThreadKeyData(oslThreadKey Key)527 void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key)
528 {
529     if (Key != 0)
530     {
531         PTLS    pTls = (PTLS)Key;
532 
533         return (TlsGetValue( pTls->dwIndex ));
534     }
535 
536     return (NULL);
537 }
538 
539 /*****************************************************************************/
540 /* osl_setThreadKeyData */
541 /*****************************************************************************/
osl_setThreadKeyData(oslThreadKey Key,void * pData)542 sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
543 {
544     if (Key != 0)
545     {
546         PTLS    pTls = (PTLS)Key;
547         void*   pOldData = NULL;
548         BOOL    fSuccess;
549 
550         if ( pTls->pfnCallback )
551             pOldData = TlsGetValue( pTls->dwIndex );
552 
553         fSuccess = TlsSetValue( pTls->dwIndex, pData );
554 
555         if ( fSuccess && pTls->pfnCallback && pOldData )
556             pTls->pfnCallback( pOldData );
557 
558         return (sal_Bool)(fSuccess != FALSE);
559     }
560 
561     return (sal_False);
562 }
563 
564 
565 /*****************************************************************************/
566 /* osl_getThreadTextEncoding */
567 /*****************************************************************************/
568 
569 DWORD   g_dwTLSTextEncodingIndex = (DWORD)-1;
570 
571 
osl_getThreadTextEncoding(void)572 rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding(void)
573 {
574     DWORD               dwEncoding;
575     rtl_TextEncoding    _encoding;
576     BOOL                gotACP;
577 
578     if ( (DWORD)-1 == g_dwTLSTextEncodingIndex )
579         g_dwTLSTextEncodingIndex = TlsAlloc();
580 
581     dwEncoding = (DWORD)TlsGetValue( g_dwTLSTextEncodingIndex );
582     _encoding = LOWORD(dwEncoding);
583     gotACP = HIWORD(dwEncoding);
584 
585 
586     if ( !gotACP )
587     {
588         char    *pszEncoding;
589 
590         if ( NULL != (pszEncoding = getenv( "SOLAR_USER_RTL_TEXTENCODING" )) )
591             _encoding = (rtl_TextEncoding)atoi(pszEncoding);
592         else
593             _encoding = rtl_getTextEncodingFromWindowsCodePage( GetACP() );
594 
595         TlsSetValue( g_dwTLSTextEncodingIndex, (LPVOID)MAKELONG( _encoding, TRUE ) );
596     }
597 
598     return _encoding;
599 }
600 
601 /*****************************************************************************/
602 /* osl_getThreadTextEncoding */
603 /*****************************************************************************/
osl_setThreadTextEncoding(rtl_TextEncoding Encoding)604 rtl_TextEncoding SAL_CALL osl_setThreadTextEncoding( rtl_TextEncoding Encoding )
605 {
606     rtl_TextEncoding oldEncoding = osl_getThreadTextEncoding();
607 
608     TlsSetValue( g_dwTLSTextEncodingIndex, (LPVOID)MAKELONG( Encoding, TRUE) );
609 
610     return oldEncoding;
611 }
612 
613 
614 
615