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