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 .
23 #include <osl/diagnose.h>
24 #include <osl/thread.h>
25 #include <rtl/alloc.h>
27 #include <osl/interlck.h>
28 #include <rtl/tencinfo.h>
32 Thread-data structure hidden behind oslThread:
36 HANDLE m_hThread
; /* OS-handle used for all thread-functions */
37 unsigned m_ThreadId
; /* identifier for this thread */
38 sal_Int32 m_nTerminationRequested
;
39 oslWorkerFunction m_WorkerFunction
;
44 static unsigned __stdcall
oslWorkerWrapperFunction(void* pData
);
45 static oslThread
oslCreateThread(oslWorkerFunction pWorker
, void* pThreadData
, sal_uInt32 nFlags
);
47 static unsigned __stdcall
oslWorkerWrapperFunction(void* pData
)
49 osl_TThreadImpl
* pThreadImpl
= static_cast<osl_TThreadImpl
*>(pData
);
51 /* Initialize COM - Multi Threaded Apartment (MTA) for all threads */
52 CoInitializeEx(nullptr, COINIT_MULTITHREADED
); /* spawned by oslCreateThread */
54 /* call worker-function with data */
56 pThreadImpl
->m_WorkerFunction(pThreadImpl
->m_pData
);
63 static oslThread
oslCreateThread(oslWorkerFunction pWorker
,
67 osl_TThreadImpl
* pThreadImpl
;
69 /* alloc mem. for our internal data structure */
70 pThreadImpl
= static_cast<osl_TThreadImpl
*>(malloc(sizeof(osl_TThreadImpl
)));
72 OSL_ASSERT(pThreadImpl
);
74 if ( pThreadImpl
== nullptr )
79 pThreadImpl
->m_WorkerFunction
= pWorker
;
80 pThreadImpl
->m_pData
= pThreadData
;
81 pThreadImpl
->m_nTerminationRequested
= 0;
83 pThreadImpl
->m_hThread
=
84 reinterpret_cast<HANDLE
>(_beginthreadex(nullptr, /* no security */
85 0, /* default stack-size */
86 oslWorkerWrapperFunction
, /* worker-function */
87 pThreadImpl
, /* provide worker-function with data */
88 nFlags
, /* start thread immediately or suspended */
89 &pThreadImpl
->m_ThreadId
));
91 if(pThreadImpl
->m_hThread
== nullptr)
96 fprintf(stderr
, "_beginthreadex errno EAGAIN\n");
99 fprintf(stderr
, "_beginthreadex errno EINVAL\n");
102 fprintf(stderr
, "_beginthreadex errno EACCES\n");
105 fprintf(stderr
, "_beginthreadex undocumented errno ENOMEM - this means not enough VM for stack\n");
108 fprintf(stderr
, "_beginthreadex unexpected errno %d\n", errno
);
120 oslThread SAL_CALL
osl_createThread(oslWorkerFunction pWorker
,
123 return oslCreateThread(pWorker
, pThreadData
, 0);
126 oslThread SAL_CALL
osl_createSuspendedThread(oslWorkerFunction pWorker
,
129 return oslCreateThread(pWorker
, pThreadData
, CREATE_SUSPENDED
);
132 oslThreadIdentifier SAL_CALL
osl_getThreadIdentifier(oslThread Thread
)
134 osl_TThreadImpl
* pThreadImpl
= static_cast<osl_TThreadImpl
*>(Thread
);
136 if (pThreadImpl
!= nullptr)
137 return static_cast<oslThreadIdentifier
>(pThreadImpl
->m_ThreadId
);
139 return static_cast<oslThreadIdentifier
>(GetCurrentThreadId());
142 void SAL_CALL
osl_destroyThread(oslThread Thread
)
144 osl_TThreadImpl
* pThreadImpl
= static_cast<osl_TThreadImpl
*>(Thread
);
146 if (Thread
== nullptr) /* valid ptr? */
148 /* thread already destroyed or not created */
152 /* !!!! _exitthreadex does _not_ call CloseHandle !!! */
153 CloseHandle( pThreadImpl
->m_hThread
);
159 void SAL_CALL
osl_resumeThread(oslThread Thread
)
161 osl_TThreadImpl
* pThreadImpl
= static_cast<osl_TThreadImpl
*>(Thread
);
163 OSL_ASSERT(pThreadImpl
); /* valid ptr? */
165 ResumeThread(pThreadImpl
->m_hThread
);
168 void SAL_CALL
osl_suspendThread(oslThread Thread
)
170 osl_TThreadImpl
* pThreadImpl
= static_cast<osl_TThreadImpl
*>(Thread
);
172 OSL_ASSERT(pThreadImpl
); /* valid ptr? */
174 SuspendThread(pThreadImpl
->m_hThread
);
177 void SAL_CALL
osl_setThreadPriority(oslThread Thread
,
178 oslThreadPriority Priority
)
181 osl_TThreadImpl
* pThreadImpl
= static_cast<osl_TThreadImpl
*>(Thread
);
183 OSL_ASSERT(pThreadImpl
); /* valid ptr? */
185 /* map enum to WIN32 levels
186 it would be faster and more elegant to preset
187 the enums, but that would require an #ifdef in
188 the exported header, which is not desired.
192 case osl_Thread_PriorityHighest
:
193 winPriority
= THREAD_PRIORITY_HIGHEST
;
196 case osl_Thread_PriorityAboveNormal
:
197 winPriority
= THREAD_PRIORITY_ABOVE_NORMAL
;
200 case osl_Thread_PriorityNormal
:
201 winPriority
= THREAD_PRIORITY_NORMAL
;
204 case osl_Thread_PriorityBelowNormal
:
205 winPriority
= THREAD_PRIORITY_BELOW_NORMAL
;
208 case osl_Thread_PriorityLowest
:
209 winPriority
= THREAD_PRIORITY_LOWEST
;
212 case osl_Thread_PriorityUnknown
:
213 OSL_ASSERT(FALSE
); /* only fools try this...*/
215 /* let release-version behave friendly */
219 OSL_ASSERT(FALSE
); /* enum expanded, but forgotten here...*/
221 /* let release-version behave friendly */
225 SetThreadPriority(pThreadImpl
->m_hThread
, winPriority
);
228 oslThreadPriority SAL_CALL
osl_getThreadPriority(const oslThread Thread
)
231 oslThreadPriority Priority
;
233 osl_TThreadImpl
* pThreadImpl
= static_cast<osl_TThreadImpl
*>(Thread
);
235 /* invalid arguments ?*/
236 if(pThreadImpl
==nullptr || pThreadImpl
->m_hThread
==nullptr)
238 return osl_Thread_PriorityUnknown
;
242 GetThreadPriority(pThreadImpl
->m_hThread
);
244 if(winPriority
== THREAD_PRIORITY_ERROR_RETURN
)
246 return osl_Thread_PriorityUnknown
;
249 /* map WIN32 priority to enum */
252 case THREAD_PRIORITY_TIME_CRITICAL
:
253 case THREAD_PRIORITY_HIGHEST
:
254 Priority
= osl_Thread_PriorityHighest
;
257 case THREAD_PRIORITY_ABOVE_NORMAL
:
258 Priority
= osl_Thread_PriorityAboveNormal
;
261 case THREAD_PRIORITY_NORMAL
:
262 Priority
= osl_Thread_PriorityNormal
;
265 case THREAD_PRIORITY_BELOW_NORMAL
:
266 Priority
= osl_Thread_PriorityBelowNormal
;
269 case THREAD_PRIORITY_IDLE
:
270 case THREAD_PRIORITY_LOWEST
:
271 Priority
= osl_Thread_PriorityLowest
;
275 OSL_ASSERT(FALSE
); /* WIN32 API changed, incorporate new prio-level! */
277 /* release-version behaves friendly */
278 Priority
= osl_Thread_PriorityUnknown
;
284 sal_Bool SAL_CALL
osl_isThreadRunning(const oslThread Thread
)
286 osl_TThreadImpl
* pThreadImpl
= static_cast<osl_TThreadImpl
*>(Thread
);
288 /* invalid arguments ?*/
289 if(pThreadImpl
==nullptr || pThreadImpl
->m_hThread
==nullptr)
294 return WaitForSingleObject(pThreadImpl
->m_hThread
, 0) != WAIT_OBJECT_0
;
297 void SAL_CALL
osl_joinWithThread(oslThread Thread
)
299 osl_TThreadImpl
* pThreadImpl
= static_cast<osl_TThreadImpl
*>(Thread
);
301 /* invalid arguments?*/
302 if(pThreadImpl
==nullptr || pThreadImpl
->m_hThread
==nullptr)
304 /* assume thread is not running */
308 WaitForSingleObject(pThreadImpl
->m_hThread
, INFINITE
);
311 void SAL_CALL
osl_waitThread(const TimeValue
* pDelay
)
315 DWORD millisecs
= pDelay
->Seconds
* 1000L + pDelay
->Nanosec
/ 1000000L;
321 void SAL_CALL
osl_terminateThread(oslThread Thread
)
323 osl_TThreadImpl
* pThreadImpl
= static_cast<osl_TThreadImpl
*>(Thread
);
325 /* invalid arguments?*/
326 if (pThreadImpl
==nullptr || pThreadImpl
->m_hThread
==nullptr)
328 /* assume thread is not running */
332 osl_atomic_increment(&(pThreadImpl
->m_nTerminationRequested
));
335 sal_Bool SAL_CALL
osl_scheduleThread(oslThread Thread
)
337 osl_TThreadImpl
* pThreadImpl
= static_cast<osl_TThreadImpl
*>(Thread
);
341 /* invalid arguments?*/
342 if (pThreadImpl
==nullptr || pThreadImpl
->m_hThread
==nullptr)
344 /* assume thread is not running */
348 return 0 == pThreadImpl
->m_nTerminationRequested
;
351 void SAL_CALL
osl_yieldThread(void)
356 void SAL_CALL
osl_setThreadName(char const * name
) {
358 /* See <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>: */
359 #pragma pack(push, 8)
367 info
.dwType
= 0x1000;
369 info
.dwThreadID
= DWORD(-1);
373 0x406D1388, 0, sizeof info
/ sizeof (ULONG_PTR
),
374 reinterpret_cast<ULONG_PTR
*>(&info
));
375 } __except (EXCEPTION_EXECUTE_HANDLER
) {}
384 oslThreadKeyCallbackFunction pfnCallback
;
385 struct TLS_
*pNext
, *pPrev
;
388 static PTLS g_pThreadKeyList
= nullptr;
389 CRITICAL_SECTION g_ThreadKeyListCS
;
391 static void AddKeyToList( PTLS pTls
)
395 EnterCriticalSection( &g_ThreadKeyListCS
);
397 pTls
->pNext
= g_pThreadKeyList
;
398 pTls
->pPrev
= nullptr;
400 if ( g_pThreadKeyList
)
401 g_pThreadKeyList
->pPrev
= pTls
;
403 g_pThreadKeyList
= pTls
;
405 LeaveCriticalSection( &g_ThreadKeyListCS
);
409 static void RemoveKeyFromList( PTLS pTls
)
413 EnterCriticalSection( &g_ThreadKeyListCS
);
415 pTls
->pPrev
->pNext
= pTls
->pNext
;
418 OSL_ASSERT( pTls
== g_pThreadKeyList
);
419 g_pThreadKeyList
= pTls
->pNext
;
423 pTls
->pNext
->pPrev
= pTls
->pPrev
;
424 LeaveCriticalSection( &g_ThreadKeyListCS
);
428 void osl_callThreadKeyCallbackOnThreadDetach(void)
432 EnterCriticalSection( &g_ThreadKeyListCS
);
433 pTls
= g_pThreadKeyList
;
436 if ( pTls
->pfnCallback
)
438 void *pValue
= TlsGetValue( pTls
->dwIndex
);
441 pTls
->pfnCallback( pValue
);
446 LeaveCriticalSection( &g_ThreadKeyListCS
);
449 oslThreadKey SAL_CALL
osl_createThreadKey(oslThreadKeyCallbackFunction pCallback
)
451 PTLS pTls
= static_cast<PTLS
>(malloc( sizeof(TLS
) ));
455 pTls
->pfnCallback
= pCallback
;
456 if ( DWORD(-1) == (pTls
->dwIndex
= TlsAlloc()) )
462 AddKeyToList( pTls
);
468 void SAL_CALL
osl_destroyThreadKey(oslThreadKey Key
)
472 PTLS pTls
= static_cast<PTLS
>(Key
);
474 RemoveKeyFromList( pTls
);
475 TlsFree( pTls
->dwIndex
);
480 void* SAL_CALL
osl_getThreadKeyData(oslThreadKey Key
)
484 PTLS pTls
= static_cast<PTLS
>(Key
);
486 return TlsGetValue( pTls
->dwIndex
);
492 sal_Bool SAL_CALL
osl_setThreadKeyData(oslThreadKey Key
, void *pData
)
496 PTLS pTls
= static_cast<PTLS
>(Key
);
497 void* pOldData
= nullptr;
500 if ( pTls
->pfnCallback
)
501 pOldData
= TlsGetValue( pTls
->dwIndex
);
503 fSuccess
= TlsSetValue( pTls
->dwIndex
, pData
);
505 if ( fSuccess
&& pTls
->pfnCallback
&& pOldData
)
506 pTls
->pfnCallback( pOldData
);
508 return fSuccess
!= FALSE
;
514 DWORD g_dwTLSTextEncodingIndex
= DWORD(-1);
516 rtl_TextEncoding SAL_CALL
osl_getThreadTextEncoding(void)
518 DWORD_PTR dwEncoding
;
519 rtl_TextEncoding _encoding
;
522 if ( DWORD(-1) == g_dwTLSTextEncodingIndex
)
523 g_dwTLSTextEncodingIndex
= TlsAlloc();
525 dwEncoding
= reinterpret_cast<DWORD_PTR
>(TlsGetValue( g_dwTLSTextEncodingIndex
));
526 _encoding
= LOWORD(dwEncoding
);
527 gotACP
= HIWORD(dwEncoding
);
531 _encoding
= rtl_getTextEncodingFromWindowsCodePage( GetACP() );
532 TlsSetValue( g_dwTLSTextEncodingIndex
, reinterpret_cast<LPVOID
>(static_cast<DWORD_PTR
>(MAKELONG( _encoding
, TRUE
))) );
538 rtl_TextEncoding SAL_CALL
osl_setThreadTextEncoding( rtl_TextEncoding Encoding
)
540 rtl_TextEncoding oldEncoding
= osl_getThreadTextEncoding();
542 TlsSetValue( g_dwTLSTextEncodingIndex
, reinterpret_cast<LPVOID
>(static_cast<DWORD_PTR
>(MAKELONG( Encoding
, TRUE
))) );
547 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */