1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include <osl/diagnose.h>
23 #include <osl/thread.h>
24 #include <rtl/alloc.h>
26 #include <osl/interlck.h>
27 #include <rtl/tencinfo.h>
30 Thread-data structure hidden behind oslThread:
32 typedef struct _osl_TThreadImpl
34 HANDLE m_hThread
; /* OS-handle used for all thread-functions */
35 unsigned m_ThreadId
; /* identifier for this thread */
36 sal_Int32 m_nTerminationRequested
;
37 oslWorkerFunction m_WorkerFunction
;
42 static unsigned __stdcall
oslWorkerWrapperFunction(void* pData
);
43 static oslThread
oslCreateThread(oslWorkerFunction pWorker
, void* pThreadData
, sal_uInt32 nFlags
);
45 /*****************************************************************************/
46 /* oslWorkerWrapperFunction */
47 /*****************************************************************************/
48 static unsigned __stdcall
oslWorkerWrapperFunction(void* pData
)
50 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)pData
;
54 CoInitializeEx(NULL
, COINIT_MULTITHREADED
);
56 /* call worker-function with data */
58 pThreadImpl
->m_WorkerFunction(pThreadImpl
->m_pData
);
65 /*****************************************************************************/
67 /*****************************************************************************/
68 static oslThread
oslCreateThread(oslWorkerFunction pWorker
,
72 osl_TThreadImpl
* pThreadImpl
;
74 /* alloc mem. for our internal data structure */
75 pThreadImpl
= malloc(sizeof(osl_TThreadImpl
));
77 OSL_ASSERT(pThreadImpl
);
79 if ( pThreadImpl
== 0 )
84 pThreadImpl
->m_WorkerFunction
= pWorker
;
85 pThreadImpl
->m_pData
= pThreadData
;
86 pThreadImpl
->m_nTerminationRequested
= 0;
88 pThreadImpl
->m_hThread
=
89 (HANDLE
)_beginthreadex(NULL
, /* no security */
90 0, /* default stack-size */
91 oslWorkerWrapperFunction
, /* worker-function */
92 pThreadImpl
, /* provide worker-function with data */
93 nFlags
, /* start thread immediately or suspended */
94 &pThreadImpl
->m_ThreadId
);
96 if(pThreadImpl
->m_hThread
== 0)
103 return (oslThread
)pThreadImpl
;
106 /*****************************************************************************/
107 /* osl_createThread */
108 /*****************************************************************************/
109 oslThread SAL_CALL
osl_createThread(oslWorkerFunction pWorker
,
112 return oslCreateThread(pWorker
, pThreadData
, 0);
115 /*****************************************************************************/
116 /* osl_createSuspendedThread */
117 /*****************************************************************************/
118 oslThread SAL_CALL
osl_createSuspendedThread(oslWorkerFunction pWorker
,
121 return oslCreateThread(pWorker
, pThreadData
, CREATE_SUSPENDED
);
124 /*****************************************************************************/
125 /* osl_getThreadIdentifier */
126 /*****************************************************************************/
127 oslThreadIdentifier SAL_CALL
osl_getThreadIdentifier(oslThread Thread
)
129 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
131 if (pThreadImpl
!= NULL
)
132 return ((oslThreadIdentifier
)pThreadImpl
->m_ThreadId
);
134 return ((oslThreadIdentifier
)GetCurrentThreadId());
137 /*****************************************************************************/
138 /* osl_destroyThread */
139 /*****************************************************************************/
140 void SAL_CALL
osl_destroyThread(oslThread Thread
)
142 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
144 if (Thread
== 0) /* valid ptr? */
146 /* thread already destroyed or not created */
150 /* !!!! _exitthreadex does _not_ call CloseHandle !!! */
151 CloseHandle( pThreadImpl
->m_hThread
);
157 /*****************************************************************************/
158 /* osl_resumeThread */
159 /*****************************************************************************/
160 void SAL_CALL
osl_resumeThread(oslThread Thread
)
162 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
164 OSL_ASSERT(pThreadImpl
); /* valid ptr? */
166 ResumeThread(pThreadImpl
->m_hThread
);
169 /*****************************************************************************/
170 /* osl_suspendThread */
171 /*****************************************************************************/
172 void SAL_CALL
osl_suspendThread(oslThread Thread
)
174 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
176 OSL_ASSERT(pThreadImpl
); /* valid ptr? */
178 SuspendThread(pThreadImpl
->m_hThread
);
181 /*****************************************************************************/
182 /* osl_setThreadPriority */
183 /*****************************************************************************/
184 void SAL_CALL
osl_setThreadPriority(oslThread Thread
,
185 oslThreadPriority Priority
)
188 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
190 OSL_ASSERT(pThreadImpl
); /* valid ptr? */
193 /* map enum to WIN32 levels
194 it would be faster and more elegant to preset
195 the enums, but that would require an #ifdef in
196 the exported header, which is not desired.
200 case osl_Thread_PriorityHighest
:
201 winPriority
= THREAD_PRIORITY_HIGHEST
;
204 case osl_Thread_PriorityAboveNormal
:
205 winPriority
= THREAD_PRIORITY_ABOVE_NORMAL
;
208 case osl_Thread_PriorityNormal
:
209 winPriority
= THREAD_PRIORITY_NORMAL
;
212 case osl_Thread_PriorityBelowNormal
:
213 winPriority
= THREAD_PRIORITY_BELOW_NORMAL
;
216 case osl_Thread_PriorityLowest
:
217 winPriority
= THREAD_PRIORITY_LOWEST
;
220 case osl_Thread_PriorityUnknown
:
221 OSL_ASSERT(FALSE
); /* only fools try this...*/
223 /* let release-version behave friendly */
227 OSL_ASSERT(FALSE
); /* enum expanded, but forgotten here...*/
229 /* let release-version behave friendly */
233 SetThreadPriority(pThreadImpl
->m_hThread
, winPriority
);
236 /*****************************************************************************/
237 /* osl_getThreadPriority */
238 /*****************************************************************************/
239 oslThreadPriority SAL_CALL
osl_getThreadPriority(const oslThread Thread
)
242 oslThreadPriority Priority
;
244 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
246 /* invalid arguments ?*/
247 if(pThreadImpl
==0 || pThreadImpl
->m_hThread
==0)
249 return osl_Thread_PriorityUnknown
;
253 GetThreadPriority(pThreadImpl
->m_hThread
);
256 if(winPriority
== THREAD_PRIORITY_ERROR_RETURN
)
258 return osl_Thread_PriorityUnknown
;
261 /* map WIN32 priority to enum */
264 case THREAD_PRIORITY_TIME_CRITICAL
:
265 case THREAD_PRIORITY_HIGHEST
:
266 Priority
= osl_Thread_PriorityHighest
;
269 case THREAD_PRIORITY_ABOVE_NORMAL
:
270 Priority
= osl_Thread_PriorityAboveNormal
;
273 case THREAD_PRIORITY_NORMAL
:
274 Priority
= osl_Thread_PriorityNormal
;
277 case THREAD_PRIORITY_BELOW_NORMAL
:
278 Priority
= osl_Thread_PriorityBelowNormal
;
281 case THREAD_PRIORITY_IDLE
:
282 case THREAD_PRIORITY_LOWEST
:
283 Priority
= osl_Thread_PriorityLowest
;
287 OSL_ASSERT(FALSE
); /* WIN32 API changed, incorporate new prio-level! */
289 /* release-version behaves friendly */
290 Priority
= osl_Thread_PriorityUnknown
;
296 /*****************************************************************************/
297 /* osl_isThreadRunning */
298 /*****************************************************************************/
299 sal_Bool SAL_CALL
osl_isThreadRunning(const oslThread Thread
)
301 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
303 /* invalid arguments ?*/
304 if(pThreadImpl
==0 || pThreadImpl
->m_hThread
==0)
309 return (sal_Bool
)(WaitForSingleObject(pThreadImpl
->m_hThread
, 0) != WAIT_OBJECT_0
);
312 /*****************************************************************************/
313 /* osl_joinWithThread */
314 /*****************************************************************************/
315 void SAL_CALL
osl_joinWithThread(oslThread Thread
)
317 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
319 /* invalid arguments?*/
320 if(pThreadImpl
==0 || pThreadImpl
->m_hThread
==0)
322 /* assume thread is not running */
326 WaitForSingleObject(pThreadImpl
->m_hThread
, INFINITE
);
329 /*****************************************************************************/
331 /*****************************************************************************/
332 void SAL_CALL
osl_waitThread(const TimeValue
* pDelay
)
336 DWORD millisecs
= pDelay
->Seconds
* 1000L + pDelay
->Nanosec
/ 1000000L;
342 /*****************************************************************************/
343 /* osl_terminateThread */
344 /*****************************************************************************/
345 void SAL_CALL
osl_terminateThread(oslThread Thread
)
347 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
349 /* invalid arguments?*/
350 if (pThreadImpl
==0 || pThreadImpl
->m_hThread
==0)
352 /* assume thread is not running */
356 osl_atomic_increment(&(pThreadImpl
->m_nTerminationRequested
));
360 /*****************************************************************************/
361 /* osl_scheduleThread */
362 /*****************************************************************************/
363 sal_Bool SAL_CALL
osl_scheduleThread(oslThread Thread
)
365 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
369 /* invalid arguments?*/
370 if (pThreadImpl
==0 || pThreadImpl
->m_hThread
==0)
372 /* assume thread is not running */
376 return (sal_Bool
)(0 == pThreadImpl
->m_nTerminationRequested
);
379 /*****************************************************************************/
380 /* osl_yieldThread */
381 /*****************************************************************************/
382 void SAL_CALL
osl_yieldThread(void)
387 void SAL_CALL
osl_setThreadName(char const * name
) {
389 /* See <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>: */
390 #pragma pack(push, 8)
398 info
.dwType
= 0x1000;
400 info
.dwThreadID
= (DWORD
) -1;
404 0x406D1388, 0, sizeof info
/ sizeof (ULONG_PTR
),
405 (ULONG_PTR
*) &info
);
406 } __except (EXCEPTION_EXECUTE_HANDLER
) {}
415 oslThreadKeyCallbackFunction pfnCallback
;
416 struct _TLS
*pNext
, *pPrev
;
419 static PTLS g_pThreadKeyList
= NULL
;
420 CRITICAL_SECTION g_ThreadKeyListCS
;
422 static void AddKeyToList( PTLS pTls
)
426 EnterCriticalSection( &g_ThreadKeyListCS
);
428 pTls
->pNext
= g_pThreadKeyList
;
431 if ( g_pThreadKeyList
)
432 g_pThreadKeyList
->pPrev
= pTls
;
434 g_pThreadKeyList
= pTls
;
436 LeaveCriticalSection( &g_ThreadKeyListCS
);
440 static void RemoveKeyFromList( PTLS pTls
)
444 EnterCriticalSection( &g_ThreadKeyListCS
);
446 pTls
->pPrev
->pNext
= pTls
->pNext
;
449 OSL_ASSERT( pTls
== g_pThreadKeyList
);
450 g_pThreadKeyList
= pTls
->pNext
;
454 pTls
->pNext
->pPrev
= pTls
->pPrev
;
455 LeaveCriticalSection( &g_ThreadKeyListCS
);
459 void SAL_CALL
_osl_callThreadKeyCallbackOnThreadDetach(void)
464 EnterCriticalSection( &g_ThreadKeyListCS
);
465 pTls
= g_pThreadKeyList
;
468 if ( pTls
->pfnCallback
)
470 void *pValue
= TlsGetValue( pTls
->dwIndex
);
473 pTls
->pfnCallback( pValue
);
478 LeaveCriticalSection( &g_ThreadKeyListCS
);
481 /*****************************************************************************/
482 /* osl_createThreadKey */
483 /*****************************************************************************/
484 oslThreadKey SAL_CALL
osl_createThreadKey(oslThreadKeyCallbackFunction pCallback
)
486 PTLS pTls
= rtl_allocateMemory( sizeof(TLS
) );
490 pTls
->pfnCallback
= pCallback
;
491 if ( (DWORD
)-1 == (pTls
->dwIndex
= TlsAlloc()) )
493 rtl_freeMemory( pTls
);
497 AddKeyToList( pTls
);
500 return ((oslThreadKey
)pTls
);
503 /*****************************************************************************/
504 /* osl_destroyThreadKey */
505 /*****************************************************************************/
506 void SAL_CALL
osl_destroyThreadKey(oslThreadKey Key
)
510 PTLS pTls
= (PTLS
)Key
;
512 RemoveKeyFromList( pTls
);
513 TlsFree( pTls
->dwIndex
);
514 rtl_freeMemory( pTls
);
518 /*****************************************************************************/
519 /* osl_getThreadKeyData */
520 /*****************************************************************************/
521 void* SAL_CALL
osl_getThreadKeyData(oslThreadKey Key
)
525 PTLS pTls
= (PTLS
)Key
;
527 return (TlsGetValue( pTls
->dwIndex
));
533 /*****************************************************************************/
534 /* osl_setThreadKeyData */
535 /*****************************************************************************/
536 sal_Bool SAL_CALL
osl_setThreadKeyData(oslThreadKey Key
, void *pData
)
540 PTLS pTls
= (PTLS
)Key
;
541 void* pOldData
= NULL
;
544 if ( pTls
->pfnCallback
)
545 pOldData
= TlsGetValue( pTls
->dwIndex
);
547 fSuccess
= TlsSetValue( pTls
->dwIndex
, pData
);
549 if ( fSuccess
&& pTls
->pfnCallback
&& pOldData
)
550 pTls
->pfnCallback( pOldData
);
552 return (sal_Bool
)(fSuccess
!= FALSE
);
559 /*****************************************************************************/
560 /* osl_getThreadTextEncoding */
561 /*****************************************************************************/
563 DWORD g_dwTLSTextEncodingIndex
= (DWORD
)-1;
566 rtl_TextEncoding SAL_CALL
osl_getThreadTextEncoding(void)
568 DWORD_PTR dwEncoding
;
569 rtl_TextEncoding _encoding
;
572 if ( (DWORD
)-1 == g_dwTLSTextEncodingIndex
)
573 g_dwTLSTextEncodingIndex
= TlsAlloc();
575 dwEncoding
= (DWORD_PTR
)TlsGetValue( g_dwTLSTextEncodingIndex
);
576 _encoding
= LOWORD(dwEncoding
);
577 gotACP
= HIWORD(dwEncoding
);
581 _encoding
= rtl_getTextEncodingFromWindowsCodePage( GetACP() );
582 TlsSetValue( g_dwTLSTextEncodingIndex
, (LPVOID
)(DWORD_PTR
)MAKELONG( _encoding
, TRUE
) );
588 /*****************************************************************************/
589 /* osl_getThreadTextEncoding */
590 /*****************************************************************************/
591 rtl_TextEncoding SAL_CALL
osl_setThreadTextEncoding( rtl_TextEncoding Encoding
)
593 rtl_TextEncoding oldEncoding
= osl_getThreadTextEncoding();
595 TlsSetValue( g_dwTLSTextEncodingIndex
, (LPVOID
)(DWORD_PTR
)MAKELONG( Encoding
, TRUE
) );
602 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */