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