Version 4.2.0.1, tag libreoffice-4.2.0.1
[LibreOffice.git] / sal / osl / w32 / thread.c
blob0bb71722694f55bf8679ae1d278f0846b0b56972
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include "system.h"
22 #include <osl/diagnose.h>
23 #include <osl/thread.h>
24 #include <rtl/alloc.h>
25 #include <osl/time.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;
38 void* m_pData;
40 } osl_TThreadImpl;
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;
52 /* Initialize COM */
54 CoInitializeEx(NULL, COINIT_MULTITHREADED);
56 /* call worker-function with data */
58 pThreadImpl->m_WorkerFunction(pThreadImpl->m_pData);
60 CoUninitialize();
62 return (0);
65 /*****************************************************************************/
66 /* oslCreateThread */
67 /*****************************************************************************/
68 static oslThread oslCreateThread(oslWorkerFunction pWorker,
69 void* pThreadData,
70 sal_uInt32 nFlags)
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 )
81 return 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)
98 /* create failed */
99 free(pThreadImpl);
100 return 0;
103 return (oslThread)pThreadImpl;
106 /*****************************************************************************/
107 /* osl_createThread */
108 /*****************************************************************************/
109 oslThread SAL_CALL osl_createThread(oslWorkerFunction pWorker,
110 void* pThreadData)
112 return oslCreateThread(pWorker, pThreadData, 0);
115 /*****************************************************************************/
116 /* osl_createSuspendedThread */
117 /*****************************************************************************/
118 oslThread SAL_CALL osl_createSuspendedThread(oslWorkerFunction pWorker,
119 void* pThreadData)
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);
133 else
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 */
147 return;
150 /* !!!! _exitthreadex does _not_ call CloseHandle !!! */
151 CloseHandle( pThreadImpl->m_hThread );
153 /* free memory */
154 free(Thread);
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)
187 int winPriority;
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.
198 switch(Priority) {
200 case osl_Thread_PriorityHighest:
201 winPriority= THREAD_PRIORITY_HIGHEST;
202 break;
204 case osl_Thread_PriorityAboveNormal:
205 winPriority= THREAD_PRIORITY_ABOVE_NORMAL;
206 break;
208 case osl_Thread_PriorityNormal:
209 winPriority= THREAD_PRIORITY_NORMAL;
210 break;
212 case osl_Thread_PriorityBelowNormal:
213 winPriority= THREAD_PRIORITY_BELOW_NORMAL;
214 break;
216 case osl_Thread_PriorityLowest:
217 winPriority= THREAD_PRIORITY_LOWEST;
218 break;
220 case osl_Thread_PriorityUnknown:
221 OSL_ASSERT(FALSE); /* only fools try this...*/
223 /* let release-version behave friendly */
224 return;
226 default:
227 OSL_ASSERT(FALSE); /* enum expanded, but forgotten here...*/
229 /* let release-version behave friendly */
230 return;
233 SetThreadPriority(pThreadImpl->m_hThread, winPriority);
236 /*****************************************************************************/
237 /* osl_getThreadPriority */
238 /*****************************************************************************/
239 oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread)
241 int winPriority;
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;
252 winPriority=
253 GetThreadPriority(pThreadImpl->m_hThread);
256 if(winPriority == THREAD_PRIORITY_ERROR_RETURN)
258 return osl_Thread_PriorityUnknown;
261 /* map WIN32 priority to enum */
262 switch(winPriority)
264 case THREAD_PRIORITY_TIME_CRITICAL:
265 case THREAD_PRIORITY_HIGHEST:
266 Priority= osl_Thread_PriorityHighest;
267 break;
269 case THREAD_PRIORITY_ABOVE_NORMAL:
270 Priority= osl_Thread_PriorityAboveNormal;
271 break;
273 case THREAD_PRIORITY_NORMAL:
274 Priority= osl_Thread_PriorityNormal;
275 break;
277 case THREAD_PRIORITY_BELOW_NORMAL:
278 Priority= osl_Thread_PriorityBelowNormal;
279 break;
281 case THREAD_PRIORITY_IDLE:
282 case THREAD_PRIORITY_LOWEST:
283 Priority= osl_Thread_PriorityLowest;
284 break;
286 default:
287 OSL_ASSERT(FALSE); /* WIN32 API changed, incorporate new prio-level! */
289 /* release-version behaves friendly */
290 Priority= osl_Thread_PriorityUnknown;
293 return Priority;
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)
306 return sal_False;
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 */
323 return;
326 WaitForSingleObject(pThreadImpl->m_hThread, INFINITE);
329 /*****************************************************************************/
330 /* osl_waitThread */
331 /*****************************************************************************/
332 void SAL_CALL osl_waitThread(const TimeValue* pDelay)
334 if (pDelay)
336 DWORD millisecs = pDelay->Seconds * 1000L + pDelay->Nanosec / 1000000L;
338 Sleep(millisecs);
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 */
353 return;
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;
367 osl_yieldThread();
369 /* invalid arguments?*/
370 if (pThreadImpl==0 || pThreadImpl->m_hThread==0)
372 /* assume thread is not running */
373 return sal_False;
376 return (sal_Bool)(0 == pThreadImpl->m_nTerminationRequested);
379 /*****************************************************************************/
380 /* osl_yieldThread */
381 /*****************************************************************************/
382 void SAL_CALL osl_yieldThread(void)
384 Sleep(0);
387 void SAL_CALL osl_setThreadName(char const * name) {
388 #ifdef _MSC_VER
389 /* See <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>: */
390 #pragma pack(push, 8)
391 struct {
392 DWORD dwType;
393 LPCSTR szName;
394 DWORD dwThreadID;
395 DWORD dwFlags;
396 } info;
397 #pragma pack(pop)
398 info.dwType = 0x1000;
399 info.szName = name;
400 info.dwThreadID = (DWORD) -1;
401 info.dwFlags = 0;
402 __try {
403 RaiseException(
404 0x406D1388, 0, sizeof info / sizeof (ULONG_PTR),
405 (ULONG_PTR *) &info);
406 } __except (EXCEPTION_EXECUTE_HANDLER) {}
407 #else
408 (void) name;
409 #endif
412 typedef struct _TLS
414 DWORD dwIndex;
415 oslThreadKeyCallbackFunction pfnCallback;
416 struct _TLS *pNext, *pPrev;
417 } TLS, *PTLS;
419 static PTLS g_pThreadKeyList = NULL;
420 CRITICAL_SECTION g_ThreadKeyListCS;
422 static void AddKeyToList( PTLS pTls )
424 if ( pTls )
426 EnterCriticalSection( &g_ThreadKeyListCS );
428 pTls->pNext = g_pThreadKeyList;
429 pTls->pPrev = 0;
431 if ( g_pThreadKeyList )
432 g_pThreadKeyList->pPrev = pTls;
434 g_pThreadKeyList = pTls;
436 LeaveCriticalSection( &g_ThreadKeyListCS );
440 static void RemoveKeyFromList( PTLS pTls )
442 if ( pTls )
444 EnterCriticalSection( &g_ThreadKeyListCS );
445 if ( pTls->pPrev )
446 pTls->pPrev->pNext = pTls->pNext;
447 else
449 OSL_ASSERT( pTls == g_pThreadKeyList );
450 g_pThreadKeyList = pTls->pNext;
453 if ( pTls->pNext )
454 pTls->pNext->pPrev = pTls->pPrev;
455 LeaveCriticalSection( &g_ThreadKeyListCS );
459 void SAL_CALL _osl_callThreadKeyCallbackOnThreadDetach(void)
461 PTLS pTls;
464 EnterCriticalSection( &g_ThreadKeyListCS );
465 pTls = g_pThreadKeyList;
466 while ( pTls )
468 if ( pTls->pfnCallback )
470 void *pValue = TlsGetValue( pTls->dwIndex );
472 if ( pValue )
473 pTls->pfnCallback( pValue );
476 pTls = pTls->pNext;
478 LeaveCriticalSection( &g_ThreadKeyListCS );
481 /*****************************************************************************/
482 /* osl_createThreadKey */
483 /*****************************************************************************/
484 oslThreadKey SAL_CALL osl_createThreadKey(oslThreadKeyCallbackFunction pCallback)
486 PTLS pTls = rtl_allocateMemory( sizeof(TLS) );
488 if ( pTls )
490 pTls->pfnCallback = pCallback;
491 if ( (DWORD)-1 == (pTls->dwIndex = TlsAlloc()) )
493 rtl_freeMemory( pTls );
494 pTls = 0;
496 else
497 AddKeyToList( pTls );
500 return ((oslThreadKey)pTls);
503 /*****************************************************************************/
504 /* osl_destroyThreadKey */
505 /*****************************************************************************/
506 void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
508 if (Key != 0)
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)
523 if (Key != 0)
525 PTLS pTls = (PTLS)Key;
527 return (TlsGetValue( pTls->dwIndex ));
530 return (NULL);
533 /*****************************************************************************/
534 /* osl_setThreadKeyData */
535 /*****************************************************************************/
536 sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
538 if (Key != 0)
540 PTLS pTls = (PTLS)Key;
541 void* pOldData = NULL;
542 BOOL fSuccess;
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);
555 return (sal_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;
570 BOOL gotACP;
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);
579 if ( !gotACP )
581 _encoding = rtl_getTextEncodingFromWindowsCodePage( GetACP() );
582 TlsSetValue( g_dwTLSTextEncodingIndex, (LPVOID)(DWORD_PTR)MAKELONG( _encoding, TRUE ) );
585 return _encoding;
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) );
597 return oldEncoding;
602 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */