1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "system.h"
25
26 #include <osl/diagnose.h>
27 #include <osl/thread.h>
28 #include <rtl/alloc.h>
29 #include <osl/time.h>
30 #include <osl/interlck.h>
31 #include <rtl/tencinfo.h>
32
33 /*
34 Thread-data structure hidden behind oslThread:
35 */
36 typedef struct _osl_TThreadImpl
37 {
38 HANDLE m_hThread; /* OS-handle used for all thread-functions */
39 unsigned m_ThreadId; /* identifier for this thread */
40 sal_Int32 m_nTerminationRequested;
41 oslWorkerFunction m_WorkerFunction;
42 void* m_pData;
43
44 } osl_TThreadImpl;
45
46 #define THREADIMPL_FLAGS_TERMINATE 0x0001
47
48 static unsigned __stdcall oslWorkerWrapperFunction(void* pData);
49 static oslThread oslCreateThread(oslWorkerFunction pWorker, void* pThreadData, sal_uInt32 nFlags);
50
51 /*****************************************************************************/
52 /* oslWorkerWrapperFunction */
53 /*****************************************************************************/
oslWorkerWrapperFunction(void * pData)54 static unsigned __stdcall oslWorkerWrapperFunction(void* pData)
55 {
56 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)pData;
57
58 /* Initialize COM */
59
60 CoInitializeEx(NULL, COINIT_MULTITHREADED);
61
62 /* call worker-function with data */
63
64 pThreadImpl->m_WorkerFunction(pThreadImpl->m_pData);
65
66 CoUninitialize();
67
68 return (0);
69 }
70
71 /*****************************************************************************/
72 /* oslCreateThread */
73 /*****************************************************************************/
oslCreateThread(oslWorkerFunction pWorker,void * pThreadData,sal_uInt32 nFlags)74 static oslThread oslCreateThread(oslWorkerFunction pWorker,
75 void* pThreadData,
76 sal_uInt32 nFlags)
77 {
78 osl_TThreadImpl* pThreadImpl;
79
80 /* alloc mem. for our internal data structure */
81 pThreadImpl= malloc(sizeof(osl_TThreadImpl));
82
83 OSL_ASSERT(pThreadImpl);
84
85 if ( pThreadImpl == 0 )
86 {
87 return 0;
88 }
89
90 pThreadImpl->m_WorkerFunction= pWorker;
91 pThreadImpl->m_pData= pThreadData;
92 pThreadImpl->m_nTerminationRequested= 0;
93
94 pThreadImpl->m_hThread=
95 (HANDLE)_beginthreadex(NULL, /* no security */
96 0, /* default stack-size */
97 oslWorkerWrapperFunction, /* worker-function */
98 pThreadImpl, /* provide worker-function with data */
99 nFlags, /* start thread immediately or suspended */
100 &pThreadImpl->m_ThreadId);
101
102 if(pThreadImpl->m_hThread == 0)
103 {
104 /* create failed */
105 free(pThreadImpl);
106 return 0;
107 }
108
109 return (oslThread)pThreadImpl;
110 }
111
112 /*****************************************************************************/
113 /* osl_createThread */
114 /*****************************************************************************/
osl_createThread(oslWorkerFunction pWorker,void * pThreadData)115 oslThread SAL_CALL osl_createThread(oslWorkerFunction pWorker,
116 void* pThreadData)
117 {
118 return oslCreateThread(pWorker, pThreadData, 0);
119 }
120
121 /*****************************************************************************/
122 /* osl_createSuspendedThread */
123 /*****************************************************************************/
osl_createSuspendedThread(oslWorkerFunction pWorker,void * pThreadData)124 oslThread SAL_CALL osl_createSuspendedThread(oslWorkerFunction pWorker,
125 void* pThreadData)
126 {
127 return oslCreateThread(pWorker, pThreadData, CREATE_SUSPENDED);
128 }
129
130 /*****************************************************************************/
131 /* osl_getThreadIdentifier */
132 /*****************************************************************************/
osl_getThreadIdentifier(oslThread Thread)133 oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread)
134 {
135 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
136
137 if (pThreadImpl != NULL)
138 return ((oslThreadIdentifier)pThreadImpl->m_ThreadId);
139 else
140 return ((oslThreadIdentifier)GetCurrentThreadId());
141 }
142
143 /*****************************************************************************/
144 /* osl_destroyThread */
145 /*****************************************************************************/
osl_destroyThread(oslThread Thread)146 void SAL_CALL osl_destroyThread(oslThread Thread)
147 {
148 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
149
150 if (Thread == 0) /* valid ptr? */
151 {
152 /* thread already destroyed or not created */
153 return;
154 }
155
156 /* !!!! _exitthreadex does _not_ call CloseHandle !!! */
157 CloseHandle( pThreadImpl->m_hThread );
158
159 /* free memory */
160 free(Thread);
161 }
162
163 /*****************************************************************************/
164 /* osl_resumeThread */
165 /*****************************************************************************/
osl_resumeThread(oslThread Thread)166 void SAL_CALL osl_resumeThread(oslThread Thread)
167 {
168 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
169
170 OSL_ASSERT(pThreadImpl); /* valid ptr? */
171
172 ResumeThread(pThreadImpl->m_hThread);
173 }
174
175 /*****************************************************************************/
176 /* osl_suspendThread */
177 /*****************************************************************************/
osl_suspendThread(oslThread Thread)178 void SAL_CALL osl_suspendThread(oslThread Thread)
179 {
180 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
181
182 OSL_ASSERT(pThreadImpl); /* valid ptr? */
183
184 SuspendThread(pThreadImpl->m_hThread);
185 }
186
187 /*****************************************************************************/
188 /* osl_setThreadPriority */
189 /*****************************************************************************/
osl_setThreadPriority(oslThread Thread,oslThreadPriority Priority)190 void SAL_CALL osl_setThreadPriority(oslThread Thread,
191 oslThreadPriority Priority)
192 {
193 int winPriority;
194 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
195
196 OSL_ASSERT(pThreadImpl); /* valid ptr? */
197
198
199 /* map enum to WIN32 levels
200 it would be faster and more elegant to preset
201 the enums, but that would require an #ifdef in
202 the exported header, which is not desired.
203 */
204 switch(Priority) {
205
206 case osl_Thread_PriorityHighest:
207 winPriority= THREAD_PRIORITY_HIGHEST;
208 break;
209
210 case osl_Thread_PriorityAboveNormal:
211 winPriority= THREAD_PRIORITY_ABOVE_NORMAL;
212 break;
213
214 case osl_Thread_PriorityNormal:
215 winPriority= THREAD_PRIORITY_NORMAL;
216 break;
217
218 case osl_Thread_PriorityBelowNormal:
219 winPriority= THREAD_PRIORITY_BELOW_NORMAL;
220 break;
221
222 case osl_Thread_PriorityLowest:
223 winPriority= THREAD_PRIORITY_LOWEST;
224 break;
225
226 case osl_Thread_PriorityUnknown:
227 OSL_ASSERT(FALSE); /* only fools try this...*/
228
229 /* let release-version behave friendly */
230 return;
231
232 default:
233 OSL_ASSERT(FALSE); /* enum expanded, but forgotten here...*/
234
235 /* let release-version behave friendly */
236 return;
237 }
238
239 SetThreadPriority(pThreadImpl->m_hThread, winPriority);
240 }
241
242 /*****************************************************************************/
243 /* osl_getThreadPriority */
244 /*****************************************************************************/
osl_getThreadPriority(const oslThread Thread)245 oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread)
246 {
247 int winPriority;
248 oslThreadPriority Priority;
249
250 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
251
252 /* invalid arguments ?*/
253 if(pThreadImpl==0 || pThreadImpl->m_hThread==0)
254 {
255 return osl_Thread_PriorityUnknown;
256 }
257
258 winPriority=
259 GetThreadPriority(pThreadImpl->m_hThread);
260
261
262 if(winPriority == THREAD_PRIORITY_ERROR_RETURN)
263 {
264 return osl_Thread_PriorityUnknown;
265 }
266
267 /* map WIN32 priority to enum */
268 switch(winPriority)
269 {
270 case THREAD_PRIORITY_TIME_CRITICAL:
271 case THREAD_PRIORITY_HIGHEST:
272 Priority= osl_Thread_PriorityHighest;
273 break;
274
275 case THREAD_PRIORITY_ABOVE_NORMAL:
276 Priority= osl_Thread_PriorityAboveNormal;
277 break;
278
279 case THREAD_PRIORITY_NORMAL:
280 Priority= osl_Thread_PriorityNormal;
281 break;
282
283 case THREAD_PRIORITY_BELOW_NORMAL:
284 Priority= osl_Thread_PriorityBelowNormal;
285 break;
286
287 case THREAD_PRIORITY_IDLE:
288 case THREAD_PRIORITY_LOWEST:
289 Priority= osl_Thread_PriorityLowest;
290 break;
291
292 default:
293 OSL_ASSERT(FALSE); /* WIN32 API changed, incorporate new prio-level! */
294
295 /* release-version behaves friendly */
296 Priority= osl_Thread_PriorityUnknown;
297 }
298
299 return Priority;
300 }
301
302 /*****************************************************************************/
303 /* osl_isThreadRunning */
304 /*****************************************************************************/
osl_isThreadRunning(const oslThread Thread)305 sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
306 {
307 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
308
309 /* invalid arguments ?*/
310 if(pThreadImpl==0 || pThreadImpl->m_hThread==0)
311 {
312 return sal_False;
313 }
314
315 return (sal_Bool)(WaitForSingleObject(pThreadImpl->m_hThread, 0) != WAIT_OBJECT_0);
316 }
317
318 /*****************************************************************************/
319 /* osl_joinWithThread */
320 /*****************************************************************************/
osl_joinWithThread(oslThread Thread)321 void SAL_CALL osl_joinWithThread(oslThread Thread)
322 {
323 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
324
325 /* invalid arguments?*/
326 if(pThreadImpl==0 || pThreadImpl->m_hThread==0)
327 {
328 /* assume thread is not running */
329 return;
330 }
331
332 WaitForSingleObject(pThreadImpl->m_hThread, INFINITE);
333 }
334
335 /*****************************************************************************/
336 /* osl_waitThread */
337 /*****************************************************************************/
osl_waitThread(const TimeValue * pDelay)338 void SAL_CALL osl_waitThread(const TimeValue* pDelay)
339 {
340 if (pDelay)
341 {
342 DWORD millisecs = pDelay->Seconds * 1000L + pDelay->Nanosec / 1000000L;
343
344 Sleep(millisecs);
345 }
346 }
347
348 /*****************************************************************************/
349 /* osl_terminateThread */
350 /*****************************************************************************/
osl_terminateThread(oslThread Thread)351 void SAL_CALL osl_terminateThread(oslThread Thread)
352 {
353 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
354
355 /* invalid arguments?*/
356 if (pThreadImpl==0 || pThreadImpl->m_hThread==0)
357 {
358 /* assume thread is not running */
359 return;
360 }
361
362 osl_incrementInterlockedCount(&(pThreadImpl->m_nTerminationRequested));
363 }
364
365
366 /*****************************************************************************/
367 /* osl_scheduleThread */
368 /*****************************************************************************/
osl_scheduleThread(oslThread Thread)369 sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread)
370 {
371 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
372
373 osl_yieldThread();
374
375 /* invalid arguments?*/
376 if (pThreadImpl==0 || pThreadImpl->m_hThread==0)
377 {
378 /* assume thread is not running */
379 return sal_False;
380 }
381
382 return (sal_Bool)(0 == pThreadImpl->m_nTerminationRequested);
383 }
384
385 /*****************************************************************************/
386 /* osl_yieldThread */
387 /*****************************************************************************/
osl_yieldThread(void)388 void SAL_CALL osl_yieldThread(void)
389 {
390 Sleep(0);
391 }
392
osl_setThreadName(char const * name)393 void SAL_CALL osl_setThreadName(char const * name) {
394 #ifdef _MSC_VER
395 /* See <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>: */
396 #pragma pack(push, 8)
397 struct {
398 DWORD dwType;
399 LPCSTR szName;
400 DWORD dwThreadID;
401 DWORD dwFlags;
402 } info;
403 #pragma pack(pop)
404 info.dwType = 0x1000;
405 info.szName = name;
406 info.dwThreadID = (DWORD) -1;
407 info.dwFlags = 0;
408 __try {
409 RaiseException(
410 0x406D1388, 0, sizeof info / sizeof (ULONG_PTR),
411 (ULONG_PTR *) &info);
412 } __except (EXCEPTION_EXECUTE_HANDLER) {}
413 #else
414 (void) name;
415 #endif
416 }
417
418 typedef struct _TLS
419 {
420 DWORD dwIndex;
421 oslThreadKeyCallbackFunction pfnCallback;
422 struct _TLS *pNext, *pPrev;
423 } TLS, *PTLS;
424
425 static PTLS g_pThreadKeyList = NULL;
426 CRITICAL_SECTION g_ThreadKeyListCS;
427
AddKeyToList(PTLS pTls)428 static void AddKeyToList( PTLS pTls )
429 {
430 if ( pTls )
431 {
432 EnterCriticalSection( &g_ThreadKeyListCS );
433
434 pTls->pNext = g_pThreadKeyList;
435 pTls->pPrev = 0;
436
437 if ( g_pThreadKeyList )
438 g_pThreadKeyList->pPrev = pTls;
439
440 g_pThreadKeyList = pTls;
441
442 LeaveCriticalSection( &g_ThreadKeyListCS );
443 }
444 }
445
RemoveKeyFromList(PTLS pTls)446 static void RemoveKeyFromList( PTLS pTls )
447 {
448 if ( pTls )
449 {
450 EnterCriticalSection( &g_ThreadKeyListCS );
451 if ( pTls->pPrev )
452 pTls->pPrev->pNext = pTls->pNext;
453 else
454 {
455 OSL_ASSERT( pTls == g_pThreadKeyList );
456 g_pThreadKeyList = pTls->pNext;
457 }
458
459 if ( pTls->pNext )
460 pTls->pNext->pPrev = pTls->pPrev;
461 LeaveCriticalSection( &g_ThreadKeyListCS );
462 }
463 }
464
_osl_callThreadKeyCallbackOnThreadDetach(void)465 void SAL_CALL _osl_callThreadKeyCallbackOnThreadDetach(void)
466 {
467 PTLS pTls;
468
469
470 EnterCriticalSection( &g_ThreadKeyListCS );
471 pTls = g_pThreadKeyList;
472 while ( pTls )
473 {
474 if ( pTls->pfnCallback )
475 {
476 void *pValue = TlsGetValue( pTls->dwIndex );
477
478 if ( pValue )
479 pTls->pfnCallback( pValue );
480 }
481
482 pTls = pTls->pNext;
483 }
484 LeaveCriticalSection( &g_ThreadKeyListCS );
485 }
486
487 /*****************************************************************************/
488 /* osl_createThreadKey */
489 /*****************************************************************************/
osl_createThreadKey(oslThreadKeyCallbackFunction pCallback)490 oslThreadKey SAL_CALL osl_createThreadKey(oslThreadKeyCallbackFunction pCallback)
491 {
492 PTLS pTls = rtl_allocateMemory( sizeof(TLS) );
493
494 if ( pTls )
495 {
496 pTls->pfnCallback = pCallback;
497 if ( (DWORD)-1 == (pTls->dwIndex = TlsAlloc()) )
498 {
499 rtl_freeMemory( pTls );
500 pTls = 0;
501 }
502 else
503 AddKeyToList( pTls );
504 }
505
506 return ((oslThreadKey)pTls);
507 }
508
509 /*****************************************************************************/
510 /* osl_destroyThreadKey */
511 /*****************************************************************************/
osl_destroyThreadKey(oslThreadKey Key)512 void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
513 {
514 if (Key != 0)
515 {
516 PTLS pTls = (PTLS)Key;
517
518 RemoveKeyFromList( pTls );
519 TlsFree( pTls->dwIndex );
520 rtl_freeMemory( pTls );
521 }
522 }
523
524 /*****************************************************************************/
525 /* osl_getThreadKeyData */
526 /*****************************************************************************/
osl_getThreadKeyData(oslThreadKey Key)527 void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key)
528 {
529 if (Key != 0)
530 {
531 PTLS pTls = (PTLS)Key;
532
533 return (TlsGetValue( pTls->dwIndex ));
534 }
535
536 return (NULL);
537 }
538
539 /*****************************************************************************/
540 /* osl_setThreadKeyData */
541 /*****************************************************************************/
osl_setThreadKeyData(oslThreadKey Key,void * pData)542 sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
543 {
544 if (Key != 0)
545 {
546 PTLS pTls = (PTLS)Key;
547 void* pOldData = NULL;
548 BOOL fSuccess;
549
550 if ( pTls->pfnCallback )
551 pOldData = TlsGetValue( pTls->dwIndex );
552
553 fSuccess = TlsSetValue( pTls->dwIndex, pData );
554
555 if ( fSuccess && pTls->pfnCallback && pOldData )
556 pTls->pfnCallback( pOldData );
557
558 return (sal_Bool)(fSuccess != FALSE);
559 }
560
561 return (sal_False);
562 }
563
564
565 /*****************************************************************************/
566 /* osl_getThreadTextEncoding */
567 /*****************************************************************************/
568
569 DWORD g_dwTLSTextEncodingIndex = (DWORD)-1;
570
571
osl_getThreadTextEncoding(void)572 rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding(void)
573 {
574 DWORD dwEncoding;
575 rtl_TextEncoding _encoding;
576 BOOL gotACP;
577
578 if ( (DWORD)-1 == g_dwTLSTextEncodingIndex )
579 g_dwTLSTextEncodingIndex = TlsAlloc();
580
581 dwEncoding = (DWORD)TlsGetValue( g_dwTLSTextEncodingIndex );
582 _encoding = LOWORD(dwEncoding);
583 gotACP = HIWORD(dwEncoding);
584
585
586 if ( !gotACP )
587 {
588 char *pszEncoding;
589
590 if ( NULL != (pszEncoding = getenv( "SOLAR_USER_RTL_TEXTENCODING" )) )
591 _encoding = (rtl_TextEncoding)atoi(pszEncoding);
592 else
593 _encoding = rtl_getTextEncodingFromWindowsCodePage( GetACP() );
594
595 TlsSetValue( g_dwTLSTextEncodingIndex, (LPVOID)MAKELONG( _encoding, TRUE ) );
596 }
597
598 return _encoding;
599 }
600
601 /*****************************************************************************/
602 /* osl_getThreadTextEncoding */
603 /*****************************************************************************/
osl_setThreadTextEncoding(rtl_TextEncoding Encoding)604 rtl_TextEncoding SAL_CALL osl_setThreadTextEncoding( rtl_TextEncoding Encoding )
605 {
606 rtl_TextEncoding oldEncoding = osl_getThreadTextEncoding();
607
608 TlsSetValue( g_dwTLSTextEncodingIndex, (LPVOID)MAKELONG( Encoding, TRUE) );
609
610 return oldEncoding;
611 }
612
613
614
615