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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 /*****************************************************************************/ 388 void SAL_CALL osl_yieldThread(void) 389 { 390 Sleep(0); 391 } 392 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 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 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 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 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 /*****************************************************************************/ 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