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