1 /** 2 * threads.c: set of generic threading related routines 3 * 4 * See Copyright for the status of this software. 5 * 6 * Gary Pennington <Gary.Pennington@uk.sun.com> 7 * daniel@veillard.com 8 */ 9 10 #define IN_LIBXML 11 #include "libxml.h" 12 13 #include <string.h> 14 15 #include <libxml/threads.h> 16 #include <libxml/globals.h> 17 18 #ifdef HAVE_SYS_TYPES_H 19 #include <sys/types.h> 20 #endif 21 #ifdef HAVE_UNISTD_H 22 #include <unistd.h> 23 #endif 24 #ifdef HAVE_STDLIB_H 25 #include <stdlib.h> 26 #endif 27 #ifdef HAVE_PTHREAD_H 28 #include <pthread.h> 29 #elif defined HAVE_WIN32_THREADS 30 //#define WIN32_LEAN_AND_MEAN 31 //#include <windows.h> 32 #ifndef HAVE_COMPILER_TLS 33 #include <process.h> 34 #endif 35 #endif 36 37 #ifdef HAVE_BEOS_THREADS 38 #include <OS.h> 39 #include <TLS.h> 40 #endif 41 42 #if defined(SOLARIS) 43 #include <note.h> 44 #endif 45 46 /* #define DEBUG_THREADS */ 47 48 #ifdef HAVE_PTHREAD_H 49 50 static int libxml_is_threaded = -1; 51 #if defined(__GNUC__) && defined(__GLIBC__) 52 #ifdef __linux__ 53 #if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ > 3) 54 #pragma weak pthread_once 55 #pragma weak pthread_getspecific 56 #pragma weak pthread_setspecific 57 #pragma weak pthread_key_create 58 #pragma weak pthread_key_delete 59 #pragma weak pthread_mutex_init 60 #pragma weak pthread_mutex_destroy 61 #pragma weak pthread_mutex_lock 62 #pragma weak pthread_mutex_unlock 63 #pragma weak pthread_cond_init 64 #pragma weak pthread_cond_destroy 65 #pragma weak pthread_cond_wait 66 #pragma weak pthread_equal 67 #pragma weak pthread_self 68 #pragma weak pthread_key_create 69 #pragma weak pthread_key_delete 70 #pragma weak pthread_cond_signal 71 #endif 72 #endif /* __linux__ */ 73 #endif /* defined(__GNUC__) && defined(__GLIBC__) */ 74 #endif /* HAVE_PTHREAD_H */ 75 76 /* 77 * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree 78 * to avoid some crazyness since xmlMalloc/xmlFree may actually 79 * be hosted on allocated blocks needing them for the allocation ... 80 */ 81 82 /* 83 * xmlMutex are a simple mutual exception locks 84 */ 85 struct _xmlMutex { 86 #ifdef HAVE_PTHREAD_H 87 pthread_mutex_t lock; 88 #elif defined HAVE_WIN32_THREADS 89 HANDLE mutex; 90 #elif defined HAVE_BEOS_THREADS 91 sem_id sem; 92 thread_id tid; 93 #else 94 int empty; 95 #endif 96 }; 97 98 /* 99 * xmlRMutex are reentrant mutual exception locks 100 */ 101 struct _xmlRMutex { 102 #ifdef HAVE_PTHREAD_H 103 pthread_mutex_t lock; 104 unsigned int held; 105 unsigned int waiters; 106 pthread_t tid; 107 pthread_cond_t cv; 108 #elif defined HAVE_WIN32_THREADS 109 CRITICAL_SECTION cs; 110 unsigned int count; 111 #elif defined HAVE_BEOS_THREADS 112 xmlMutexPtr lock; 113 thread_id tid; 114 int32 count; 115 #else 116 int empty; 117 #endif 118 }; 119 120 /* 121 * This module still has some internal static data. 122 * - xmlLibraryLock a global lock 123 * - globalkey used for per-thread data 124 */ 125 126 #ifdef HAVE_PTHREAD_H 127 static pthread_key_t globalkey; 128 static pthread_t mainthread; 129 static pthread_once_t once_control = PTHREAD_ONCE_INIT; 130 static pthread_once_t once_control_init = PTHREAD_ONCE_INIT; 131 static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER; 132 #elif defined HAVE_WIN32_THREADS 133 #if defined(HAVE_COMPILER_TLS) 134 static __declspec(thread) xmlGlobalState tlstate; 135 static __declspec(thread) int tlstate_inited = 0; 136 #else /* HAVE_COMPILER_TLS */ 137 static DWORD globalkey = TLS_OUT_OF_INDEXES; 138 #endif /* HAVE_COMPILER_TLS */ 139 static DWORD mainthread; 140 static struct { 141 DWORD done; 142 LONG control; 143 } run_once = { 0, 0}; 144 static volatile LPCRITICAL_SECTION global_init_lock = NULL; 145 146 /* endif HAVE_WIN32_THREADS */ 147 #elif defined HAVE_BEOS_THREADS 148 int32 globalkey = 0; 149 thread_id mainthread = 0; 150 int32 run_once_init = 0; 151 static int32 global_init_lock = -1; 152 static vint32 global_init_count = 0; 153 #endif 154 155 static xmlRMutexPtr xmlLibraryLock = NULL; 156 157 #ifdef LIBXML_THREAD_ENABLED 158 static void xmlOnceInit(void); 159 #endif 160 161 /** 162 * xmlNewMutex: 163 * 164 * xmlNewMutex() is used to allocate a libxml2 token struct for use in 165 * synchronizing access to data. 166 * 167 * Returns a new simple mutex pointer or NULL in case of error 168 */ 169 xmlMutexPtr 170 xmlNewMutex(void) 171 { 172 xmlMutexPtr tok; 173 174 if ((tok = malloc(sizeof(xmlMutex))) == NULL) 175 return (NULL); 176 #ifdef HAVE_PTHREAD_H 177 if (libxml_is_threaded != 0) 178 pthread_mutex_init(&tok->lock, NULL); 179 #elif defined HAVE_WIN32_THREADS 180 tok->mutex = CreateMutex(NULL, FALSE, NULL); 181 #elif defined HAVE_BEOS_THREADS 182 if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) { 183 free(tok); 184 return NULL; 185 } 186 tok->tid = -1; 187 #endif 188 return (tok); 189 } 190 191 /** 192 * xmlFreeMutex: 193 * @tok: the simple mutex 194 * 195 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token 196 * struct. 197 */ 198 void 199 xmlFreeMutex(xmlMutexPtr tok) 200 { 201 if (tok == NULL) 202 return; 203 204 #ifdef HAVE_PTHREAD_H 205 if (libxml_is_threaded != 0) 206 pthread_mutex_destroy(&tok->lock); 207 #elif defined HAVE_WIN32_THREADS 208 CloseHandle(tok->mutex); 209 #elif defined HAVE_BEOS_THREADS 210 delete_sem(tok->sem); 211 #endif 212 free(tok); 213 } 214 215 /** 216 * xmlMutexLock: 217 * @tok: the simple mutex 218 * 219 * xmlMutexLock() is used to lock a libxml2 token. 220 */ 221 void 222 xmlMutexLock(xmlMutexPtr tok) 223 { 224 if (tok == NULL) 225 return; 226 #ifdef HAVE_PTHREAD_H 227 if (libxml_is_threaded != 0) 228 pthread_mutex_lock(&tok->lock); 229 #elif defined HAVE_WIN32_THREADS 230 WaitForSingleObject(tok->mutex, INFINITE); 231 #elif defined HAVE_BEOS_THREADS 232 if (acquire_sem(tok->sem) != B_NO_ERROR) { 233 #ifdef DEBUG_THREADS 234 xmlGenericError(xmlGenericErrorContext, 235 "xmlMutexLock():BeOS:Couldn't aquire semaphore\n"); 236 #endif 237 } 238 tok->tid = find_thread(NULL); 239 #endif 240 241 } 242 243 /** 244 * xmlMutexUnlock: 245 * @tok: the simple mutex 246 * 247 * xmlMutexUnlock() is used to unlock a libxml2 token. 248 */ 249 void 250 xmlMutexUnlock(xmlMutexPtr tok) 251 { 252 if (tok == NULL) 253 return; 254 #ifdef HAVE_PTHREAD_H 255 if (libxml_is_threaded != 0) 256 pthread_mutex_unlock(&tok->lock); 257 #elif defined HAVE_WIN32_THREADS 258 ReleaseMutex(tok->mutex); 259 #elif defined HAVE_BEOS_THREADS 260 if (tok->tid == find_thread(NULL)) { 261 tok->tid = -1; 262 release_sem(tok->sem); 263 } 264 #endif 265 } 266 267 /** 268 * xmlNewRMutex: 269 * 270 * xmlRNewMutex() is used to allocate a reentrant mutex for use in 271 * synchronizing access to data. token_r is a re-entrant lock and thus useful 272 * for synchronizing access to data structures that may be manipulated in a 273 * recursive fashion. 274 * 275 * Returns the new reentrant mutex pointer or NULL in case of error 276 */ 277 xmlRMutexPtr 278 xmlNewRMutex(void) 279 { 280 xmlRMutexPtr tok; 281 282 if ((tok = malloc(sizeof(xmlRMutex))) == NULL) 283 return (NULL); 284 #ifdef HAVE_PTHREAD_H 285 if (libxml_is_threaded != 0) { 286 pthread_mutex_init(&tok->lock, NULL); 287 tok->held = 0; 288 tok->waiters = 0; 289 pthread_cond_init(&tok->cv, NULL); 290 } 291 #elif defined HAVE_WIN32_THREADS 292 InitializeCriticalSection(&tok->cs); 293 tok->count = 0; 294 #elif defined HAVE_BEOS_THREADS 295 if ((tok->lock = xmlNewMutex()) == NULL) { 296 free(tok); 297 return NULL; 298 } 299 tok->count = 0; 300 #endif 301 return (tok); 302 } 303 304 /** 305 * xmlFreeRMutex: 306 * @tok: the reentrant mutex 307 * 308 * xmlRFreeMutex() is used to reclaim resources associated with a 309 * reentrant mutex. 310 */ 311 void 312 xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED) 313 { 314 if (tok == NULL) 315 return; 316 #ifdef HAVE_PTHREAD_H 317 if (libxml_is_threaded != 0) { 318 pthread_mutex_destroy(&tok->lock); 319 pthread_cond_destroy(&tok->cv); 320 } 321 #elif defined HAVE_WIN32_THREADS 322 DeleteCriticalSection(&tok->cs); 323 #elif defined HAVE_BEOS_THREADS 324 xmlFreeMutex(tok->lock); 325 #endif 326 free(tok); 327 } 328 329 /** 330 * xmlRMutexLock: 331 * @tok: the reentrant mutex 332 * 333 * xmlRMutexLock() is used to lock a libxml2 token_r. 334 */ 335 void 336 xmlRMutexLock(xmlRMutexPtr tok) 337 { 338 if (tok == NULL) 339 return; 340 #ifdef HAVE_PTHREAD_H 341 if (libxml_is_threaded == 0) 342 return; 343 344 pthread_mutex_lock(&tok->lock); 345 if (tok->held) { 346 if (pthread_equal(tok->tid, pthread_self())) { 347 tok->held++; 348 pthread_mutex_unlock(&tok->lock); 349 return; 350 } else { 351 tok->waiters++; 352 while (tok->held) 353 pthread_cond_wait(&tok->cv, &tok->lock); 354 tok->waiters--; 355 } 356 } 357 tok->tid = pthread_self(); 358 tok->held = 1; 359 pthread_mutex_unlock(&tok->lock); 360 #elif defined HAVE_WIN32_THREADS 361 EnterCriticalSection(&tok->cs); 362 tok->count++; 363 #elif defined HAVE_BEOS_THREADS 364 if (tok->lock->tid == find_thread(NULL)) { 365 tok->count++; 366 return; 367 } else { 368 xmlMutexLock(tok->lock); 369 tok->count = 1; 370 } 371 #endif 372 } 373 374 /** 375 * xmlRMutexUnlock: 376 * @tok: the reentrant mutex 377 * 378 * xmlRMutexUnlock() is used to unlock a libxml2 token_r. 379 */ 380 void 381 xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED) 382 { 383 if (tok == NULL) 384 return; 385 #ifdef HAVE_PTHREAD_H 386 if (libxml_is_threaded == 0) 387 return; 388 389 pthread_mutex_lock(&tok->lock); 390 tok->held--; 391 if (tok->held == 0) { 392 if (tok->waiters) 393 pthread_cond_signal(&tok->cv); 394 memset(&tok->tid, 0, sizeof(tok->tid)); 395 } 396 pthread_mutex_unlock(&tok->lock); 397 #elif defined HAVE_WIN32_THREADS 398 if (tok->count > 0) { 399 tok->count--; 400 LeaveCriticalSection(&tok->cs); 401 } 402 #elif defined HAVE_BEOS_THREADS 403 if (tok->lock->tid == find_thread(NULL)) { 404 tok->count--; 405 if (tok->count == 0) { 406 xmlMutexUnlock(tok->lock); 407 } 408 return; 409 } 410 #endif 411 } 412 413 /** 414 * xmlGlobalInitMutexLock 415 * 416 * Makes sure that the global initialization mutex is initialized and 417 * locks it. 418 */ 419 void 420 __xmlGlobalInitMutexLock(void) 421 { 422 /* Make sure the global init lock is initialized and then lock it. */ 423 #ifdef HAVE_PTHREAD_H 424 /* The mutex is statically initialized, so we just lock it. */ 425 if (pthread_mutex_lock != NULL) 426 pthread_mutex_lock(&global_init_lock); 427 #elif defined HAVE_WIN32_THREADS 428 LPCRITICAL_SECTION cs; 429 430 /* Create a new critical section */ 431 if (global_init_lock == NULL) { 432 cs = malloc(sizeof(CRITICAL_SECTION)); 433 if (cs == NULL) { 434 xmlGenericError(xmlGenericErrorContext, 435 "xmlGlobalInitMutexLock: out of memory\n"); 436 return; 437 } 438 InitializeCriticalSection(cs); 439 440 /* Swap it into the global_init_lock */ 441 #ifdef InterlockedCompareExchangePointer 442 InterlockedCompareExchangePointer((void **) &global_init_lock, 443 cs, NULL); 444 #else /* Use older void* version */ 445 InterlockedCompareExchange((void **) &global_init_lock, 446 (void *) cs, NULL); 447 #endif /* InterlockedCompareExchangePointer */ 448 449 /* If another thread successfully recorded its critical 450 * section in the global_init_lock then discard the one 451 * allocated by this thread. */ 452 if (global_init_lock != cs) { 453 DeleteCriticalSection(cs); 454 free(cs); 455 } 456 } 457 458 /* Lock the chosen critical section */ 459 EnterCriticalSection(global_init_lock); 460 #elif defined HAVE_BEOS_THREADS 461 int32 sem; 462 463 /* Allocate a new semaphore */ 464 sem = create_sem(1, "xmlGlobalinitMutex"); 465 466 while (global_init_lock == -1) { 467 if (atomic_add(&global_init_count, 1) == 0) { 468 global_init_lock = sem; 469 } else { 470 snooze(1); 471 atomic_add(&global_init_count, -1); 472 } 473 } 474 475 /* If another thread successfully recorded its critical 476 * section in the global_init_lock then discard the one 477 * allocated by this thread. */ 478 if (global_init_lock != sem) 479 delete_sem(sem); 480 481 /* Acquire the chosen semaphore */ 482 if (acquire_sem(global_init_lock) != B_NO_ERROR) { 483 #ifdef DEBUG_THREADS 484 xmlGenericError(xmlGenericErrorContext, 485 "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n"); 486 #endif 487 } 488 #endif 489 } 490 491 void 492 __xmlGlobalInitMutexUnlock(void) 493 { 494 #ifdef HAVE_PTHREAD_H 495 if (pthread_mutex_unlock != NULL) 496 pthread_mutex_unlock(&global_init_lock); 497 #elif defined HAVE_WIN32_THREADS 498 if (global_init_lock != NULL) { 499 LeaveCriticalSection(global_init_lock); 500 } 501 #elif defined HAVE_BEOS_THREADS 502 release_sem(global_init_lock); 503 #endif 504 } 505 506 /** 507 * xmlGlobalInitMutexDestroy 508 * 509 * Makes sure that the global initialization mutex is destroyed before 510 * application termination. 511 */ 512 void 513 __xmlGlobalInitMutexDestroy(void) 514 { 515 #ifdef HAVE_PTHREAD_H 516 #elif defined HAVE_WIN32_THREADS 517 if (global_init_lock != NULL) { 518 DeleteCriticalSection(global_init_lock); 519 free(global_init_lock); 520 global_init_lock = NULL; 521 } 522 #endif 523 } 524 525 /************************************************************************ 526 * * 527 * Per thread global state handling * 528 * * 529 ************************************************************************/ 530 531 #ifdef LIBXML_THREAD_ENABLED 532 #ifdef xmlLastError 533 #undef xmlLastError 534 #endif 535 536 /** 537 * xmlFreeGlobalState: 538 * @state: a thread global state 539 * 540 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL 541 * global state. It is is used here to reclaim memory resources. 542 */ 543 static void 544 xmlFreeGlobalState(void *state) 545 { 546 xmlGlobalState *gs = (xmlGlobalState *) state; 547 548 /* free any memory allocated in the thread's xmlLastError */ 549 xmlResetError(&(gs->xmlLastError)); 550 free(state); 551 } 552 553 /** 554 * xmlNewGlobalState: 555 * 556 * xmlNewGlobalState() allocates a global state. This structure is used to 557 * hold all data for use by a thread when supporting backwards compatibility 558 * of libxml2 to pre-thread-safe behaviour. 559 * 560 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error 561 */ 562 static xmlGlobalStatePtr 563 xmlNewGlobalState(void) 564 { 565 xmlGlobalState *gs; 566 567 gs = malloc(sizeof(xmlGlobalState)); 568 if (gs == NULL) { 569 xmlGenericError(xmlGenericErrorContext, 570 "xmlGetGlobalState: out of memory\n"); 571 return (NULL); 572 } 573 574 memset(gs, 0, sizeof(xmlGlobalState)); 575 xmlInitializeGlobalState(gs); 576 return (gs); 577 } 578 #endif /* LIBXML_THREAD_ENABLED */ 579 580 #ifdef HAVE_PTHREAD_H 581 #elif defined HAVE_WIN32_THREADS 582 #if !defined(HAVE_COMPILER_TLS) 583 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) 584 typedef struct _xmlGlobalStateCleanupHelperParams { 585 HANDLE thread; 586 void *memory; 587 } xmlGlobalStateCleanupHelperParams; 588 589 static void XMLCDECL 590 xmlGlobalStateCleanupHelper(void *p) 591 { 592 xmlGlobalStateCleanupHelperParams *params = 593 (xmlGlobalStateCleanupHelperParams *) p; 594 WaitForSingleObject(params->thread, INFINITE); 595 CloseHandle(params->thread); 596 xmlFreeGlobalState(params->memory); 597 free(params); 598 _endthread(); 599 } 600 #else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */ 601 602 typedef struct _xmlGlobalStateCleanupHelperParams { 603 void *memory; 604 struct _xmlGlobalStateCleanupHelperParams *prev; 605 struct _xmlGlobalStateCleanupHelperParams *next; 606 } xmlGlobalStateCleanupHelperParams; 607 608 static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL; 609 static CRITICAL_SECTION cleanup_helpers_cs; 610 611 #endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */ 612 #endif /* HAVE_COMPILER_TLS */ 613 #endif /* HAVE_WIN32_THREADS */ 614 615 #if defined HAVE_BEOS_THREADS 616 617 /** 618 * xmlGlobalStateCleanup: 619 * @data: unused parameter 620 * 621 * Used for Beos only 622 */ 623 void 624 xmlGlobalStateCleanup(void *data) 625 { 626 void *globalval = tls_get(globalkey); 627 628 if (globalval != NULL) 629 xmlFreeGlobalState(globalval); 630 } 631 #endif 632 633 /** 634 * xmlGetGlobalState: 635 * 636 * xmlGetGlobalState() is called to retrieve the global state for a thread. 637 * 638 * Returns the thread global state or NULL in case of error 639 */ 640 xmlGlobalStatePtr 641 xmlGetGlobalState(void) 642 { 643 #ifdef HAVE_PTHREAD_H 644 xmlGlobalState *globalval; 645 646 if (libxml_is_threaded == 0) 647 return (NULL); 648 649 pthread_once(&once_control, xmlOnceInit); 650 651 if ((globalval = (xmlGlobalState *) 652 pthread_getspecific(globalkey)) == NULL) { 653 xmlGlobalState *tsd = xmlNewGlobalState(); 654 if (tsd == NULL) 655 return(NULL); 656 657 pthread_setspecific(globalkey, tsd); 658 return (tsd); 659 } 660 return (globalval); 661 #elif defined HAVE_WIN32_THREADS 662 #if defined(HAVE_COMPILER_TLS) 663 if (!tlstate_inited) { 664 tlstate_inited = 1; 665 xmlInitializeGlobalState(&tlstate); 666 } 667 return &tlstate; 668 #else /* HAVE_COMPILER_TLS */ 669 xmlGlobalState *globalval; 670 xmlGlobalStateCleanupHelperParams *p; 671 672 xmlOnceInit(); 673 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) 674 globalval = (xmlGlobalState *) TlsGetValue(globalkey); 675 #else 676 p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey); 677 globalval = (xmlGlobalState *) (p ? p->memory : NULL); 678 #endif 679 if (globalval == NULL) { 680 xmlGlobalState *tsd = xmlNewGlobalState(); 681 682 if (tsd == NULL) 683 return(NULL); 684 p = (xmlGlobalStateCleanupHelperParams *) 685 malloc(sizeof(xmlGlobalStateCleanupHelperParams)); 686 if (p == NULL) { 687 xmlGenericError(xmlGenericErrorContext, 688 "xmlGetGlobalState: out of memory\n"); 689 xmlFreeGlobalState(tsd); 690 return(NULL); 691 } 692 p->memory = tsd; 693 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) 694 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), 695 GetCurrentProcess(), &p->thread, 0, TRUE, 696 DUPLICATE_SAME_ACCESS); 697 TlsSetValue(globalkey, tsd); 698 _beginthread(xmlGlobalStateCleanupHelper, 0, p); 699 #else 700 EnterCriticalSection(&cleanup_helpers_cs); 701 if (cleanup_helpers_head != NULL) { 702 cleanup_helpers_head->prev = p; 703 } 704 p->next = cleanup_helpers_head; 705 p->prev = NULL; 706 cleanup_helpers_head = p; 707 TlsSetValue(globalkey, p); 708 LeaveCriticalSection(&cleanup_helpers_cs); 709 #endif 710 711 return (tsd); 712 } 713 return (globalval); 714 #endif /* HAVE_COMPILER_TLS */ 715 #elif defined HAVE_BEOS_THREADS 716 xmlGlobalState *globalval; 717 718 xmlOnceInit(); 719 720 if ((globalval = (xmlGlobalState *) tls_get(globalkey)) == NULL) { 721 xmlGlobalState *tsd = xmlNewGlobalState(); 722 if (tsd == NULL) 723 return (NULL); 724 725 tls_set(globalkey, tsd); 726 on_exit_thread(xmlGlobalStateCleanup, NULL); 727 return (tsd); 728 } 729 return (globalval); 730 #else 731 return (NULL); 732 #endif 733 } 734 735 /************************************************************************ 736 * * 737 * Library wide thread interfaces * 738 * * 739 ************************************************************************/ 740 741 /** 742 * xmlGetThreadId: 743 * 744 * xmlGetThreadId() find the current thread ID number 745 * Note that this is likely to be broken on some platforms using pthreads 746 * as the specification doesn't mandate pthread_t to be an integer type 747 * 748 * Returns the current thread ID number 749 */ 750 int 751 xmlGetThreadId(void) 752 { 753 #ifdef HAVE_PTHREAD_H 754 pthread_t id; 755 int ret; 756 757 if (libxml_is_threaded == 0) 758 return (0); 759 id = pthread_self(); 760 /* horrible but preserves compat, see warning above */ 761 memcpy(&ret, &id, sizeof(ret)); 762 return (ret); 763 #elif defined HAVE_WIN32_THREADS 764 return GetCurrentThreadId(); 765 #elif defined HAVE_BEOS_THREADS 766 return find_thread(NULL); 767 #else 768 return ((int) 0); 769 #endif 770 } 771 772 /** 773 * xmlIsMainThread: 774 * 775 * xmlIsMainThread() check whether the current thread is the main thread. 776 * 777 * Returns 1 if the current thread is the main thread, 0 otherwise 778 */ 779 int 780 xmlIsMainThread(void) 781 { 782 #ifdef HAVE_PTHREAD_H 783 if (libxml_is_threaded == -1) 784 xmlInitThreads(); 785 if (libxml_is_threaded == 0) 786 return (1); 787 pthread_once(&once_control, xmlOnceInit); 788 #elif defined HAVE_WIN32_THREADS 789 xmlOnceInit(); 790 #elif defined HAVE_BEOS_THREADS 791 xmlOnceInit(); 792 #endif 793 794 #ifdef DEBUG_THREADS 795 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n"); 796 #endif 797 #ifdef HAVE_PTHREAD_H 798 return (pthread_equal(mainthread,pthread_self())); 799 #elif defined HAVE_WIN32_THREADS 800 return (mainthread == GetCurrentThreadId()); 801 #elif defined HAVE_BEOS_THREADS 802 return (mainthread == find_thread(NULL)); 803 #else 804 return (1); 805 #endif 806 } 807 808 /** 809 * xmlLockLibrary: 810 * 811 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2 812 * library. 813 */ 814 void 815 xmlLockLibrary(void) 816 { 817 #ifdef DEBUG_THREADS 818 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n"); 819 #endif 820 xmlRMutexLock(xmlLibraryLock); 821 } 822 823 /** 824 * xmlUnlockLibrary: 825 * 826 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2 827 * library. 828 */ 829 void 830 xmlUnlockLibrary(void) 831 { 832 #ifdef DEBUG_THREADS 833 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n"); 834 #endif 835 xmlRMutexUnlock(xmlLibraryLock); 836 } 837 838 /** 839 * xmlInitThreads: 840 * 841 * xmlInitThreads() is used to to initialize all the thread related 842 * data of the libxml2 library. 843 */ 844 void 845 xmlInitThreads(void) 846 { 847 #ifdef HAVE_PTHREAD_H 848 if (libxml_is_threaded == -1) { 849 if ((pthread_once != NULL) && 850 (pthread_getspecific != NULL) && 851 (pthread_setspecific != NULL) && 852 (pthread_key_create != NULL) && 853 (pthread_key_delete != NULL) && 854 (pthread_mutex_init != NULL) && 855 (pthread_mutex_destroy != NULL) && 856 (pthread_mutex_lock != NULL) && 857 (pthread_mutex_unlock != NULL) && 858 (pthread_cond_init != NULL) && 859 (pthread_cond_destroy != NULL) && 860 (pthread_cond_wait != NULL) && 861 (pthread_equal != NULL) && 862 (pthread_self != NULL) && 863 (pthread_cond_signal != NULL)) { 864 libxml_is_threaded = 1; 865 866 /* fprintf(stderr, "Running multithreaded\n"); */ 867 } else { 868 869 /* fprintf(stderr, "Running without multithread\n"); */ 870 libxml_is_threaded = 0; 871 } 872 } 873 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) 874 InitializeCriticalSection(&cleanup_helpers_cs); 875 #endif 876 } 877 878 /** 879 * xmlCleanupThreads: 880 * 881 * xmlCleanupThreads() is used to to cleanup all the thread related 882 * data of the libxml2 library once processing has ended. 883 * 884 * WARNING: if your application is multithreaded or has plugin support 885 * calling this may crash the application if another thread or 886 * a plugin is still using libxml2. It's sometimes very hard to 887 * guess if libxml2 is in use in the application, some libraries 888 * or plugins may use it without notice. In case of doubt abstain 889 * from calling this function or do it just before calling exit() 890 * to avoid leak reports from valgrind ! 891 */ 892 void 893 xmlCleanupThreads(void) 894 { 895 #ifdef DEBUG_THREADS 896 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n"); 897 #endif 898 #ifdef HAVE_PTHREAD_H 899 if ((libxml_is_threaded) && (pthread_key_delete != NULL)) 900 pthread_key_delete(globalkey); 901 once_control = once_control_init; 902 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) 903 if (globalkey != TLS_OUT_OF_INDEXES) { 904 xmlGlobalStateCleanupHelperParams *p; 905 906 EnterCriticalSection(&cleanup_helpers_cs); 907 p = cleanup_helpers_head; 908 while (p != NULL) { 909 xmlGlobalStateCleanupHelperParams *temp = p; 910 911 p = p->next; 912 xmlFreeGlobalState(temp->memory); 913 free(temp); 914 } 915 cleanup_helpers_head = 0; 916 LeaveCriticalSection(&cleanup_helpers_cs); 917 TlsFree(globalkey); 918 globalkey = TLS_OUT_OF_INDEXES; 919 } 920 DeleteCriticalSection(&cleanup_helpers_cs); 921 #endif 922 } 923 924 #ifdef LIBXML_THREAD_ENABLED 925 926 /** 927 * xmlOnceInit 928 * 929 * xmlOnceInit() is used to initialize the value of mainthread for use 930 * in other routines. This function should only be called using 931 * pthread_once() in association with the once_control variable to ensure 932 * that the function is only called once. See man pthread_once for more 933 * details. 934 */ 935 static void 936 xmlOnceInit(void) 937 { 938 #ifdef HAVE_PTHREAD_H 939 (void) pthread_key_create(&globalkey, xmlFreeGlobalState); 940 mainthread = pthread_self(); 941 __xmlInitializeDict(); 942 #elif defined(HAVE_WIN32_THREADS) 943 if (!run_once.done) { 944 if (InterlockedIncrement(&run_once.control) == 1) { 945 #if !defined(HAVE_COMPILER_TLS) 946 globalkey = TlsAlloc(); 947 #endif 948 mainthread = GetCurrentThreadId(); 949 __xmlInitializeDict(); 950 run_once.done = 1; 951 } else { 952 /* Another thread is working; give up our slice and 953 * wait until they're done. */ 954 while (!run_once.done) 955 Sleep(0); 956 } 957 } 958 #elif defined HAVE_BEOS_THREADS 959 if (atomic_add(&run_once_init, 1) == 0) { 960 globalkey = tls_allocate(); 961 tls_set(globalkey, NULL); 962 mainthread = find_thread(NULL); 963 __xmlInitializeDict(); 964 } else 965 atomic_add(&run_once_init, -1); 966 #endif 967 } 968 #endif 969 970 /** 971 * DllMain: 972 * @hinstDLL: handle to DLL instance 973 * @fdwReason: Reason code for entry 974 * @lpvReserved: generic pointer (depends upon reason code) 975 * 976 * Entry point for Windows library. It is being used to free thread-specific 977 * storage. 978 * 979 * Returns TRUE always 980 */ 981 #ifdef HAVE_PTHREAD_H 982 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) 983 #if defined(LIBXML_STATIC_FOR_DLL) 984 int XMLCALL 985 xmlDllMain(ATTRIBUTE_UNUSED void *hinstDLL, unsigned long fdwReason, 986 ATTRIBUTE_UNUSED void *lpvReserved) 987 #else 988 /* declare to avoid "no previous prototype for 'DllMain'" warning */ 989 /* Note that we do NOT want to include this function declaration in 990 a public header because it's meant to be called by Windows itself, 991 not a program that uses this library. This also has to be exported. */ 992 993 XMLPUBFUN BOOL WINAPI 994 DllMain (HINSTANCE hinstDLL, 995 DWORD fdwReason, 996 LPVOID lpvReserved); 997 998 BOOL WINAPI 999 DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL, DWORD fdwReason, 1000 ATTRIBUTE_UNUSED LPVOID lpvReserved) 1001 #endif 1002 { 1003 switch (fdwReason) { 1004 case DLL_THREAD_DETACH: 1005 if (globalkey != TLS_OUT_OF_INDEXES) { 1006 xmlGlobalState *globalval = NULL; 1007 xmlGlobalStateCleanupHelperParams *p = 1008 (xmlGlobalStateCleanupHelperParams *) 1009 TlsGetValue(globalkey); 1010 globalval = (xmlGlobalState *) (p ? p->memory : NULL); 1011 if (globalval) { 1012 xmlFreeGlobalState(globalval); 1013 TlsSetValue(globalkey, NULL); 1014 } 1015 if (p) { 1016 EnterCriticalSection(&cleanup_helpers_cs); 1017 if (p == cleanup_helpers_head) 1018 cleanup_helpers_head = p->next; 1019 else 1020 p->prev->next = p->next; 1021 if (p->next != NULL) 1022 p->next->prev = p->prev; 1023 LeaveCriticalSection(&cleanup_helpers_cs); 1024 free(p); 1025 } 1026 } 1027 break; 1028 } 1029 return TRUE; 1030 } 1031 #endif 1032 #define bottom_threads 1033 #include "elfgcchack.h" 1034