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