1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: thread.c,v $
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 ************************************************************************/
33 #include <osl/diagnose.h>
34 #include <osl/thread.h>
35 #include <rtl/alloc.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
;
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
;
67 CoInitializeEx(NULL
, COINIT_MULTITHREADED
);
69 /* call worker-function with data */
71 pThreadImpl
->m_WorkerFunction(pThreadImpl
->m_pData
);
78 /*****************************************************************************/
80 /*****************************************************************************/
81 static oslThread
oslCreateThread(oslWorkerFunction pWorker
,
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 )
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)
116 return (oslThread
)pThreadImpl
;
119 /*****************************************************************************/
120 /* osl_createThread */
121 /*****************************************************************************/
122 oslThread SAL_CALL
osl_createThread(oslWorkerFunction pWorker
,
125 return oslCreateThread(pWorker
, pThreadData
, 0);
128 /*****************************************************************************/
129 /* osl_createSuspendedThread */
130 /*****************************************************************************/
131 oslThread SAL_CALL
osl_createSuspendedThread(oslWorkerFunction pWorker
,
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
);
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 */
163 /* !!!! _exitthreadex does _not_ call CloseHandle !!! */
164 CloseHandle( pThreadImpl
->m_hThread
);
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
)
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.
213 case osl_Thread_PriorityHighest
:
214 winPriority
= THREAD_PRIORITY_HIGHEST
;
217 case osl_Thread_PriorityAboveNormal
:
218 winPriority
= THREAD_PRIORITY_ABOVE_NORMAL
;
221 case osl_Thread_PriorityNormal
:
222 winPriority
= THREAD_PRIORITY_NORMAL
;
225 case osl_Thread_PriorityBelowNormal
:
226 winPriority
= THREAD_PRIORITY_BELOW_NORMAL
;
229 case osl_Thread_PriorityLowest
:
230 winPriority
= THREAD_PRIORITY_LOWEST
;
233 case osl_Thread_PriorityUnknown
:
234 OSL_ASSERT(FALSE
); /* only fools try this...*/
236 /* let release-version behave friendly */
240 OSL_ASSERT(FALSE
); /* enum expanded, but forgotten here...*/
242 /* let release-version behave friendly */
246 SetThreadPriority(pThreadImpl
->m_hThread
, winPriority
);
249 /*****************************************************************************/
250 /* osl_getThreadPriority */
251 /*****************************************************************************/
252 oslThreadPriority SAL_CALL
osl_getThreadPriority(const oslThread Thread
)
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
;
266 GetThreadPriority(pThreadImpl
->m_hThread
);
269 if(winPriority
== THREAD_PRIORITY_ERROR_RETURN
)
271 return osl_Thread_PriorityUnknown
;
274 /* map WIN32 priority to enum */
277 case THREAD_PRIORITY_TIME_CRITICAL
:
278 case THREAD_PRIORITY_HIGHEST
:
279 Priority
= osl_Thread_PriorityHighest
;
282 case THREAD_PRIORITY_ABOVE_NORMAL
:
283 Priority
= osl_Thread_PriorityAboveNormal
;
286 case THREAD_PRIORITY_NORMAL
:
287 Priority
= osl_Thread_PriorityNormal
;
290 case THREAD_PRIORITY_BELOW_NORMAL
:
291 Priority
= osl_Thread_PriorityBelowNormal
;
294 case THREAD_PRIORITY_IDLE
:
295 case THREAD_PRIORITY_LOWEST
:
296 Priority
= osl_Thread_PriorityLowest
;
300 OSL_ASSERT(FALSE
); /* WIN32 API changed, incorporate new prio-level! */
302 /* release-version behaves friendly */
303 Priority
= osl_Thread_PriorityUnknown
;
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)
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 */
339 WaitForSingleObject(pThreadImpl
->m_hThread
, INFINITE
);
342 /*****************************************************************************/
344 /*****************************************************************************/
345 void SAL_CALL
osl_waitThread(const TimeValue
* pDelay
)
349 DWORD millisecs
= pDelay
->Seconds
* 1000L + pDelay
->Nanosec
/ 1000000L;
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 */
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
;
382 /* invalid arguments?*/
383 if (pThreadImpl
==0 || pThreadImpl
->m_hThread
==0)
385 /* assume thread is not running */
389 return (sal_Bool
)(0 == pThreadImpl
->m_nTerminationRequested
);
392 /*****************************************************************************/
393 /* osl_yieldThread */
394 /*****************************************************************************/
395 void SAL_CALL
osl_yieldThread(void)
403 oslThreadKeyCallbackFunction pfnCallback
;
404 struct _TLS
*pNext
, *pPrev
;
407 static PTLS g_pThreadKeyList
= NULL
;
408 CRITICAL_SECTION g_ThreadKeyListCS
;
410 static void AddKeyToList( PTLS pTls
)
414 EnterCriticalSection( &g_ThreadKeyListCS
);
416 pTls
->pNext
= g_pThreadKeyList
;
419 if ( g_pThreadKeyList
)
420 g_pThreadKeyList
->pPrev
= pTls
;
422 g_pThreadKeyList
= pTls
;
424 LeaveCriticalSection( &g_ThreadKeyListCS
);
428 static void RemoveKeyFromList( PTLS pTls
)
432 EnterCriticalSection( &g_ThreadKeyListCS
);
434 pTls
->pPrev
->pNext
= pTls
->pNext
;
437 OSL_ASSERT( pTls
== g_pThreadKeyList
);
438 g_pThreadKeyList
= pTls
->pNext
;
442 pTls
->pNext
->pPrev
= pTls
->pPrev
;
443 LeaveCriticalSection( &g_ThreadKeyListCS
);
447 void SAL_CALL
_osl_callThreadKeyCallbackOnThreadDetach(void)
452 EnterCriticalSection( &g_ThreadKeyListCS
);
453 pTls
= g_pThreadKeyList
;
456 if ( pTls
->pfnCallback
)
458 void *pValue
= TlsGetValue( pTls
->dwIndex
);
461 pTls
->pfnCallback( pValue
);
466 LeaveCriticalSection( &g_ThreadKeyListCS
);
469 /*****************************************************************************/
470 /* osl_createThreadKey */
471 /*****************************************************************************/
472 oslThreadKey SAL_CALL
osl_createThreadKey(oslThreadKeyCallbackFunction pCallback
)
474 PTLS pTls
= rtl_allocateMemory( sizeof(TLS
) );
478 pTls
->pfnCallback
= pCallback
;
479 if ( (DWORD
)-1 == (pTls
->dwIndex
= TlsAlloc()) )
481 rtl_freeMemory( pTls
);
485 AddKeyToList( pTls
);
488 return ((oslThreadKey
)pTls
);
491 /*****************************************************************************/
492 /* osl_destroyThreadKey */
493 /*****************************************************************************/
494 void SAL_CALL
osl_destroyThreadKey(oslThreadKey Key
)
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
)
513 PTLS pTls
= (PTLS
)Key
;
515 return (TlsGetValue( pTls
->dwIndex
));
521 /*****************************************************************************/
522 /* osl_setThreadKeyData */
523 /*****************************************************************************/
524 sal_Bool SAL_CALL
osl_setThreadKeyData(oslThreadKey Key
, void *pData
)
528 PTLS pTls
= (PTLS
)Key
;
529 void* pOldData
= NULL
;
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
);
547 /*****************************************************************************/
548 /* osl_getThreadTextEncoding */
549 /*****************************************************************************/
551 DWORD g_dwTLSTextEncodingIndex
= (DWORD
)-1;
554 rtl_TextEncoding SAL_CALL
osl_getThreadTextEncoding(void)
557 rtl_TextEncoding _encoding
;
560 if ( (DWORD
)-1 == g_dwTLSTextEncodingIndex
)
561 g_dwTLSTextEncodingIndex
= TlsAlloc();
563 dwEncoding
= (DWORD
)TlsGetValue( g_dwTLSTextEncodingIndex
);
564 _encoding
= LOWORD(dwEncoding
);
565 gotACP
= HIWORD(dwEncoding
);
572 if ( NULL
!= (pszEncoding
= getenv( "SOLAR_USER_RTL_TEXTENCODING" )) )
573 _encoding
= (rtl_TextEncoding
)atoi(pszEncoding
);
575 _encoding
= rtl_getTextEncodingFromWindowsCodePage( GetACP() );
577 TlsSetValue( g_dwTLSTextEncodingIndex
, (LPVOID
)MAKELONG( _encoding
, TRUE
) );
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
) );