update dev300-m57
[ooovba.git] / sal / osl / w32 / thread.c
blobea6909220e9b4d7bf9c4866b96b4fc070fc03f67
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: thread.c,v $
10 * $Revision: 1.20 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "system.h"
33 #include <osl/diagnose.h>
34 #include <osl/thread.h>
35 #include <rtl/alloc.h>
36 #include <osl/time.h>
37 #include <osl/interlck.h>
38 #include <rtl/tencinfo.h>
41 Thread-data structure hidden behind oslThread:
43 typedef struct _osl_TThreadImpl
45 HANDLE m_hThread; /* OS-handle used for all thread-functions */
46 unsigned m_ThreadId; /* identifier for this thread */
47 sal_Int32 m_nTerminationRequested;
48 oslWorkerFunction m_WorkerFunction;
49 void* m_pData;
51 } osl_TThreadImpl;
53 #define THREADIMPL_FLAGS_TERMINATE 0x0001
55 static unsigned __stdcall oslWorkerWrapperFunction(void* pData);
56 static oslThread oslCreateThread(oslWorkerFunction pWorker, void* pThreadData, sal_uInt32 nFlags);
58 /*****************************************************************************/
59 /* oslWorkerWrapperFunction */
60 /*****************************************************************************/
61 static unsigned __stdcall oslWorkerWrapperFunction(void* pData)
63 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)pData;
65 /* Initialize COM */
67 CoInitializeEx(NULL, COINIT_MULTITHREADED);
69 /* call worker-function with data */
71 pThreadImpl->m_WorkerFunction(pThreadImpl->m_pData);
73 CoUninitialize();
75 return (0);
78 /*****************************************************************************/
79 /* oslCreateThread */
80 /*****************************************************************************/
81 static oslThread oslCreateThread(oslWorkerFunction pWorker,
82 void* pThreadData,
83 sal_uInt32 nFlags)
85 osl_TThreadImpl* pThreadImpl;
87 /* alloc mem. for our internal data structure */
88 pThreadImpl= malloc(sizeof(osl_TThreadImpl));
90 OSL_ASSERT(pThreadImpl);
92 if ( pThreadImpl == 0 )
94 return 0;
97 pThreadImpl->m_WorkerFunction= pWorker;
98 pThreadImpl->m_pData= pThreadData;
99 pThreadImpl->m_nTerminationRequested= 0;
101 pThreadImpl->m_hThread=
102 (HANDLE)_beginthreadex(NULL, /* no security */
103 0, /* default stack-size */
104 oslWorkerWrapperFunction, /* worker-function */
105 pThreadImpl, /* provide worker-function with data */
106 nFlags, /* start thread immediately or suspended */
107 &pThreadImpl->m_ThreadId);
109 if(pThreadImpl->m_hThread == 0)
111 /* create failed */
112 free(pThreadImpl);
113 return 0;
116 return (oslThread)pThreadImpl;
119 /*****************************************************************************/
120 /* osl_createThread */
121 /*****************************************************************************/
122 oslThread SAL_CALL osl_createThread(oslWorkerFunction pWorker,
123 void* pThreadData)
125 return oslCreateThread(pWorker, pThreadData, 0);
128 /*****************************************************************************/
129 /* osl_createSuspendedThread */
130 /*****************************************************************************/
131 oslThread SAL_CALL osl_createSuspendedThread(oslWorkerFunction pWorker,
132 void* pThreadData)
134 return oslCreateThread(pWorker, pThreadData, CREATE_SUSPENDED);
137 /*****************************************************************************/
138 /* osl_getThreadIdentifier */
139 /*****************************************************************************/
140 oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread)
142 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
144 if (pThreadImpl != NULL)
145 return ((oslThreadIdentifier)pThreadImpl->m_ThreadId);
146 else
147 return ((oslThreadIdentifier)GetCurrentThreadId());
150 /*****************************************************************************/
151 /* osl_destroyThread */
152 /*****************************************************************************/
153 void SAL_CALL osl_destroyThread(oslThread Thread)
155 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
157 if (Thread == 0) /* valid ptr? */
159 /* thread already destroyed or not created */
160 return;
163 /* !!!! _exitthreadex does _not_ call CloseHandle !!! */
164 CloseHandle( pThreadImpl->m_hThread );
166 /* free memory */
167 free(Thread);
170 /*****************************************************************************/
171 /* osl_resumeThread */
172 /*****************************************************************************/
173 void SAL_CALL osl_resumeThread(oslThread Thread)
175 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
177 OSL_ASSERT(pThreadImpl); /* valid ptr? */
179 ResumeThread(pThreadImpl->m_hThread);
182 /*****************************************************************************/
183 /* osl_suspendThread */
184 /*****************************************************************************/
185 void SAL_CALL osl_suspendThread(oslThread Thread)
187 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
189 OSL_ASSERT(pThreadImpl); /* valid ptr? */
191 SuspendThread(pThreadImpl->m_hThread);
194 /*****************************************************************************/
195 /* osl_setThreadPriority */
196 /*****************************************************************************/
197 void SAL_CALL osl_setThreadPriority(oslThread Thread,
198 oslThreadPriority Priority)
200 int winPriority;
201 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
203 OSL_ASSERT(pThreadImpl); /* valid ptr? */
206 /* map enum to WIN32 levels
207 it would be faster and more elegant to preset
208 the enums, but that would require an #ifdef in
209 the exported header, which is not desired.
211 switch(Priority) {
213 case osl_Thread_PriorityHighest:
214 winPriority= THREAD_PRIORITY_HIGHEST;
215 break;
217 case osl_Thread_PriorityAboveNormal:
218 winPriority= THREAD_PRIORITY_ABOVE_NORMAL;
219 break;
221 case osl_Thread_PriorityNormal:
222 winPriority= THREAD_PRIORITY_NORMAL;
223 break;
225 case osl_Thread_PriorityBelowNormal:
226 winPriority= THREAD_PRIORITY_BELOW_NORMAL;
227 break;
229 case osl_Thread_PriorityLowest:
230 winPriority= THREAD_PRIORITY_LOWEST;
231 break;
233 case osl_Thread_PriorityUnknown:
234 OSL_ASSERT(FALSE); /* only fools try this...*/
236 /* let release-version behave friendly */
237 return;
239 default:
240 OSL_ASSERT(FALSE); /* enum expanded, but forgotten here...*/
242 /* let release-version behave friendly */
243 return;
246 SetThreadPriority(pThreadImpl->m_hThread, winPriority);
249 /*****************************************************************************/
250 /* osl_getThreadPriority */
251 /*****************************************************************************/
252 oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread)
254 int winPriority;
255 oslThreadPriority Priority;
257 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
259 /* invalid arguments ?*/
260 if(pThreadImpl==0 || pThreadImpl->m_hThread==0)
262 return osl_Thread_PriorityUnknown;
265 winPriority=
266 GetThreadPriority(pThreadImpl->m_hThread);
269 if(winPriority == THREAD_PRIORITY_ERROR_RETURN)
271 return osl_Thread_PriorityUnknown;
274 /* map WIN32 priority to enum */
275 switch(winPriority)
277 case THREAD_PRIORITY_TIME_CRITICAL:
278 case THREAD_PRIORITY_HIGHEST:
279 Priority= osl_Thread_PriorityHighest;
280 break;
282 case THREAD_PRIORITY_ABOVE_NORMAL:
283 Priority= osl_Thread_PriorityAboveNormal;
284 break;
286 case THREAD_PRIORITY_NORMAL:
287 Priority= osl_Thread_PriorityNormal;
288 break;
290 case THREAD_PRIORITY_BELOW_NORMAL:
291 Priority= osl_Thread_PriorityBelowNormal;
292 break;
294 case THREAD_PRIORITY_IDLE:
295 case THREAD_PRIORITY_LOWEST:
296 Priority= osl_Thread_PriorityLowest;
297 break;
299 default:
300 OSL_ASSERT(FALSE); /* WIN32 API changed, incorporate new prio-level! */
302 /* release-version behaves friendly */
303 Priority= osl_Thread_PriorityUnknown;
306 return Priority;
309 /*****************************************************************************/
310 /* osl_isThreadRunning */
311 /*****************************************************************************/
312 sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
314 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
316 /* invalid arguments ?*/
317 if(pThreadImpl==0 || pThreadImpl->m_hThread==0)
319 return sal_False;
322 return (sal_Bool)(WaitForSingleObject(pThreadImpl->m_hThread, 0) != WAIT_OBJECT_0);
325 /*****************************************************************************/
326 /* osl_joinWithThread */
327 /*****************************************************************************/
328 void SAL_CALL osl_joinWithThread(oslThread Thread)
330 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
332 /* invalid arguments?*/
333 if(pThreadImpl==0 || pThreadImpl->m_hThread==0)
335 /* assume thread is not running */
336 return;
339 WaitForSingleObject(pThreadImpl->m_hThread, INFINITE);
342 /*****************************************************************************/
343 /* osl_waitThread */
344 /*****************************************************************************/
345 void SAL_CALL osl_waitThread(const TimeValue* pDelay)
347 if (pDelay)
349 DWORD millisecs = pDelay->Seconds * 1000L + pDelay->Nanosec / 1000000L;
351 Sleep(millisecs);
355 /*****************************************************************************/
356 /* osl_terminateThread */
357 /*****************************************************************************/
358 void SAL_CALL osl_terminateThread(oslThread Thread)
360 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
362 /* invalid arguments?*/
363 if (pThreadImpl==0 || pThreadImpl->m_hThread==0)
365 /* assume thread is not running */
366 return;
369 osl_incrementInterlockedCount(&(pThreadImpl->m_nTerminationRequested));
373 /*****************************************************************************/
374 /* osl_scheduleThread */
375 /*****************************************************************************/
376 sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread)
378 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
380 osl_yieldThread();
382 /* invalid arguments?*/
383 if (pThreadImpl==0 || pThreadImpl->m_hThread==0)
385 /* assume thread is not running */
386 return sal_False;
389 return (sal_Bool)(0 == pThreadImpl->m_nTerminationRequested);
392 /*****************************************************************************/
393 /* osl_yieldThread */
394 /*****************************************************************************/
395 void SAL_CALL osl_yieldThread(void)
397 Sleep(0);
400 typedef struct _TLS
402 DWORD dwIndex;
403 oslThreadKeyCallbackFunction pfnCallback;
404 struct _TLS *pNext, *pPrev;
405 } TLS, *PTLS;
407 static PTLS g_pThreadKeyList = NULL;
408 CRITICAL_SECTION g_ThreadKeyListCS;
410 static void AddKeyToList( PTLS pTls )
412 if ( pTls )
414 EnterCriticalSection( &g_ThreadKeyListCS );
416 pTls->pNext = g_pThreadKeyList;
417 pTls->pPrev = 0;
419 if ( g_pThreadKeyList )
420 g_pThreadKeyList->pPrev = pTls;
422 g_pThreadKeyList = pTls;
424 LeaveCriticalSection( &g_ThreadKeyListCS );
428 static void RemoveKeyFromList( PTLS pTls )
430 if ( pTls )
432 EnterCriticalSection( &g_ThreadKeyListCS );
433 if ( pTls->pPrev )
434 pTls->pPrev->pNext = pTls->pNext;
435 else
437 OSL_ASSERT( pTls == g_pThreadKeyList );
438 g_pThreadKeyList = pTls->pNext;
441 if ( pTls->pNext )
442 pTls->pNext->pPrev = pTls->pPrev;
443 LeaveCriticalSection( &g_ThreadKeyListCS );
447 void SAL_CALL _osl_callThreadKeyCallbackOnThreadDetach(void)
449 PTLS pTls;
452 EnterCriticalSection( &g_ThreadKeyListCS );
453 pTls = g_pThreadKeyList;
454 while ( pTls )
456 if ( pTls->pfnCallback )
458 void *pValue = TlsGetValue( pTls->dwIndex );
460 if ( pValue )
461 pTls->pfnCallback( pValue );
464 pTls = pTls->pNext;
466 LeaveCriticalSection( &g_ThreadKeyListCS );
469 /*****************************************************************************/
470 /* osl_createThreadKey */
471 /*****************************************************************************/
472 oslThreadKey SAL_CALL osl_createThreadKey(oslThreadKeyCallbackFunction pCallback)
474 PTLS pTls = rtl_allocateMemory( sizeof(TLS) );
476 if ( pTls )
478 pTls->pfnCallback = pCallback;
479 if ( (DWORD)-1 == (pTls->dwIndex = TlsAlloc()) )
481 rtl_freeMemory( pTls );
482 pTls = 0;
484 else
485 AddKeyToList( pTls );
488 return ((oslThreadKey)pTls);
491 /*****************************************************************************/
492 /* osl_destroyThreadKey */
493 /*****************************************************************************/
494 void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
496 if (Key != 0)
498 PTLS pTls = (PTLS)Key;
500 RemoveKeyFromList( pTls );
501 TlsFree( pTls->dwIndex );
502 rtl_freeMemory( pTls );
506 /*****************************************************************************/
507 /* osl_getThreadKeyData */
508 /*****************************************************************************/
509 void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key)
511 if (Key != 0)
513 PTLS pTls = (PTLS)Key;
515 return (TlsGetValue( pTls->dwIndex ));
518 return (NULL);
521 /*****************************************************************************/
522 /* osl_setThreadKeyData */
523 /*****************************************************************************/
524 sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
526 if (Key != 0)
528 PTLS pTls = (PTLS)Key;
529 void* pOldData = NULL;
530 BOOL fSuccess;
532 if ( pTls->pfnCallback )
533 pOldData = TlsGetValue( pTls->dwIndex );
535 fSuccess = TlsSetValue( pTls->dwIndex, pData );
537 if ( fSuccess && pTls->pfnCallback && pOldData )
538 pTls->pfnCallback( pOldData );
540 return (sal_Bool)(fSuccess != FALSE);
543 return (sal_False);
547 /*****************************************************************************/
548 /* osl_getThreadTextEncoding */
549 /*****************************************************************************/
551 DWORD g_dwTLSTextEncodingIndex = (DWORD)-1;
554 rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding(void)
556 DWORD dwEncoding;
557 rtl_TextEncoding _encoding;
558 BOOL gotACP;
560 if ( (DWORD)-1 == g_dwTLSTextEncodingIndex )
561 g_dwTLSTextEncodingIndex = TlsAlloc();
563 dwEncoding = (DWORD)TlsGetValue( g_dwTLSTextEncodingIndex );
564 _encoding = LOWORD(dwEncoding);
565 gotACP = HIWORD(dwEncoding);
568 if ( !gotACP )
570 char *pszEncoding;
572 if ( NULL != (pszEncoding = getenv( "SOLAR_USER_RTL_TEXTENCODING" )) )
573 _encoding = (rtl_TextEncoding)atoi(pszEncoding);
574 else
575 _encoding = rtl_getTextEncodingFromWindowsCodePage( GetACP() );
577 TlsSetValue( g_dwTLSTextEncodingIndex, (LPVOID)MAKELONG( _encoding, TRUE ) );
580 return _encoding;
583 /*****************************************************************************/
584 /* osl_getThreadTextEncoding */
585 /*****************************************************************************/
586 rtl_TextEncoding SAL_CALL osl_setThreadTextEncoding( rtl_TextEncoding Encoding )
588 rtl_TextEncoding oldEncoding = osl_getThreadTextEncoding();
590 TlsSetValue( g_dwTLSTextEncodingIndex, (LPVOID)MAKELONG( Encoding, TRUE) );
592 return oldEncoding;