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_once_t once_control_init = PTHREAD_ONCE_INIT; 150 static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER; 151 #elif defined HAVE_WIN32_THREADS 152 #if defined(HAVE_COMPILER_TLS) 153 static __declspec(thread) xmlGlobalState tlstate; 154 static __declspec(thread) int tlstate_inited = 0; 155 #else /* HAVE_COMPILER_TLS */ 156 static DWORD globalkey = TLS_OUT_OF_INDEXES; 157 #endif /* HAVE_COMPILER_TLS */ 158 static DWORD mainthread; 159 static struct { 160 DWORD done; 161 DWORD control; 162 } run_once = { 0, 0}; 163 static volatile LPCRITICAL_SECTION global_init_lock = NULL; 164 165 /* endif HAVE_WIN32_THREADS */ 166 #elif defined HAVE_BEOS_THREADS 167 int32 globalkey = 0; 168 thread_id mainthread = 0; 169 int32 run_once_init = 0; 170 static int32 global_init_lock = -1; 171 static vint32 global_init_count = 0; 172 #endif 173 174 static xmlRMutexPtr xmlLibraryLock = NULL; 175 176 #ifdef LIBXML_THREAD_ENABLED 177 static void xmlOnceInit(void); 178 #endif 179 180 /** 181 * xmlNewMutex: 182 * 183 * xmlNewMutex() is used to allocate a libxml2 token struct for use in 184 * synchronizing access to data. 185 * 186 * Returns a new simple mutex pointer or NULL in case of error 187 */ 188 xmlMutexPtr 189 xmlNewMutex(void) 190 { 191 xmlMutexPtr tok; 192 193 if ((tok = malloc(sizeof(xmlMutex))) == NULL) 194 return (NULL); 195 #ifdef HAVE_PTHREAD_H 196 if (libxml_is_threaded != 0) 197 pthread_mutex_init(&tok->lock, NULL); 198 #elif defined HAVE_WIN32_THREADS 199 tok->mutex = CreateMutex(NULL, FALSE, NULL); 200 #elif defined HAVE_BEOS_THREADS 201 if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) { 202 free(tok); 203 return NULL; 204 } 205 tok->tid = -1; 206 #endif 207 return (tok); 208 } 209 210 /** 211 * xmlFreeMutex: 212 * @tok: the simple mutex 213 * 214 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token 215 * struct. 216 */ 217 void 218 xmlFreeMutex(xmlMutexPtr tok) 219 { 220 if (tok == NULL) 221 return; 222 223 #ifdef HAVE_PTHREAD_H 224 if (libxml_is_threaded != 0) 225 pthread_mutex_destroy(&tok->lock); 226 #elif defined HAVE_WIN32_THREADS 227 CloseHandle(tok->mutex); 228 #elif defined HAVE_BEOS_THREADS 229 delete_sem(tok->sem); 230 #endif 231 free(tok); 232 } 233 234 /** 235 * xmlMutexLock: 236 * @tok: the simple mutex 237 * 238 * xmlMutexLock() is used to lock a libxml2 token. 239 */ 240 void 241 xmlMutexLock(xmlMutexPtr tok) 242 { 243 if (tok == NULL) 244 return; 245 #ifdef HAVE_PTHREAD_H 246 if (libxml_is_threaded != 0) 247 pthread_mutex_lock(&tok->lock); 248 #elif defined HAVE_WIN32_THREADS 249 WaitForSingleObject(tok->mutex, INFINITE); 250 #elif defined HAVE_BEOS_THREADS 251 if (acquire_sem(tok->sem) != B_NO_ERROR) { 252 #ifdef DEBUG_THREADS 253 xmlGenericError(xmlGenericErrorContext, 254 "xmlMutexLock():BeOS:Couldn't aquire semaphore\n"); 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 if (pthread_mutex_lock != NULL) 443 pthread_mutex_lock(&global_init_lock); 444 #elif defined HAVE_WIN32_THREADS 445 LPCRITICAL_SECTION cs; 446 447 /* Create a new critical section */ 448 if (global_init_lock == NULL) { 449 cs = malloc(sizeof(CRITICAL_SECTION)); 450 if (cs == NULL) { 451 xmlGenericError(xmlGenericErrorContext, 452 "xmlGlobalInitMutexLock: out of memory\n"); 453 return; 454 } 455 InitializeCriticalSection(cs); 456 457 /* Swap it into the global_init_lock */ 458 #ifdef InterlockedCompareExchangePointer 459 InterlockedCompareExchangePointer(&global_init_lock, cs, NULL); 460 #else /* Use older void* version */ 461 InterlockedCompareExchange((void **) &global_init_lock, 462 (void *) cs, NULL); 463 #endif /* InterlockedCompareExchangePointer */ 464 465 /* If another thread successfully recorded its critical 466 * section in the global_init_lock then discard the one 467 * allocated by this thread. */ 468 if (global_init_lock != cs) { 469 DeleteCriticalSection(cs); 470 free(cs); 471 } 472 } 473 474 /* Lock the chosen critical section */ 475 EnterCriticalSection(global_init_lock); 476 #elif defined HAVE_BEOS_THREADS 477 int32 sem; 478 479 /* Allocate a new semaphore */ 480 sem = create_sem(1, "xmlGlobalinitMutex"); 481 482 while (global_init_lock == -1) { 483 if (atomic_add(&global_init_count, 1) == 0) { 484 global_init_lock = sem; 485 } else { 486 snooze(1); 487 atomic_add(&global_init_count, -1); 488 } 489 } 490 491 /* If another thread successfully recorded its critical 492 * section in the global_init_lock then discard the one 493 * allocated by this thread. */ 494 if (global_init_lock != sem) 495 delete_sem(sem); 496 497 /* Acquire the chosen semaphore */ 498 if (acquire_sem(global_init_lock) != B_NO_ERROR) { 499 #ifdef DEBUG_THREADS 500 xmlGenericError(xmlGenericErrorContext, 501 "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n"); 502 #endif 503 } 504 #endif 505 } 506 507 void 508 __xmlGlobalInitMutexUnlock(void) 509 { 510 #ifdef HAVE_PTHREAD_H 511 if (pthread_mutex_unlock != NULL) 512 pthread_mutex_unlock(&global_init_lock); 513 #elif defined HAVE_WIN32_THREADS 514 if (global_init_lock != NULL) { 515 LeaveCriticalSection(global_init_lock); 516 } 517 #elif defined HAVE_BEOS_THREADS 518 release_sem(global_init_lock); 519 #endif 520 } 521 522 /** 523 * xmlGlobalInitMutexDestroy 524 * 525 * Makes sure that the global initialization mutex is destroyed before 526 * application termination. 527 */ 528 void 529 __xmlGlobalInitMutexDestroy(void) 530 { 531 #ifdef HAVE_PTHREAD_H 532 #elif 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 #ifdef HAVE_PTHREAD_H 597 #elif defined 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 * Note that this is likely to be broken on some platforms using pthreads 762 * as the specification doesn't mandate pthread_t to be an integer type 763 * 764 * Returns the current thread ID number 765 */ 766 int 767 xmlGetThreadId(void) 768 { 769 #ifdef HAVE_PTHREAD_H 770 pthread_t id; 771 int ret; 772 773 if (libxml_is_threaded == 0) 774 return (0); 775 id = pthread_self(); 776 /* horrible but preserves compat, see warning above */ 777 memcpy(&ret, &id, sizeof(ret)); 778 return (ret); 779 #elif defined HAVE_WIN32_THREADS 780 return GetCurrentThreadId(); 781 #elif defined HAVE_BEOS_THREADS 782 return find_thread(NULL); 783 #else 784 return ((int) 0); 785 #endif 786 } 787 788 /** 789 * xmlIsMainThread: 790 * 791 * xmlIsMainThread() check whether the current thread is the main thread. 792 * 793 * Returns 1 if the current thread is the main thread, 0 otherwise 794 */ 795 int 796 xmlIsMainThread(void) 797 { 798 #ifdef HAVE_PTHREAD_H 799 if (libxml_is_threaded == -1) 800 xmlInitThreads(); 801 if (libxml_is_threaded == 0) 802 return (1); 803 pthread_once(&once_control, xmlOnceInit); 804 #elif defined HAVE_WIN32_THREADS 805 xmlOnceInit(); 806 #elif defined HAVE_BEOS_THREADS 807 xmlOnceInit(); 808 #endif 809 810 #ifdef DEBUG_THREADS 811 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n"); 812 #endif 813 #ifdef HAVE_PTHREAD_H 814 return (pthread_equal(mainthread,pthread_self())); 815 #elif defined HAVE_WIN32_THREADS 816 return (mainthread == GetCurrentThreadId()); 817 #elif defined HAVE_BEOS_THREADS 818 return (mainthread == find_thread(NULL)); 819 #else 820 return (1); 821 #endif 822 } 823 824 /** 825 * xmlLockLibrary: 826 * 827 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2 828 * library. 829 */ 830 void 831 xmlLockLibrary(void) 832 { 833 #ifdef DEBUG_THREADS 834 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n"); 835 #endif 836 xmlRMutexLock(xmlLibraryLock); 837 } 838 839 /** 840 * xmlUnlockLibrary: 841 * 842 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2 843 * library. 844 */ 845 void 846 xmlUnlockLibrary(void) 847 { 848 #ifdef DEBUG_THREADS 849 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n"); 850 #endif 851 xmlRMutexUnlock(xmlLibraryLock); 852 } 853 854 /** 855 * xmlInitThreads: 856 * 857 * xmlInitThreads() is used to to initialize all the thread related 858 * data of the libxml2 library. 859 */ 860 void 861 xmlInitThreads(void) 862 { 863 #ifdef HAVE_PTHREAD_H 864 if (libxml_is_threaded == -1) { 865 if ((pthread_once != NULL) && 866 (pthread_getspecific != NULL) && 867 (pthread_setspecific != NULL) && 868 (pthread_key_create != NULL) && 869 (pthread_key_delete != NULL) && 870 (pthread_mutex_init != NULL) && 871 (pthread_mutex_destroy != NULL) && 872 (pthread_mutex_lock != NULL) && 873 (pthread_mutex_unlock != NULL) && 874 (pthread_cond_init != NULL) && 875 (pthread_cond_destroy != NULL) && 876 (pthread_cond_wait != NULL) && 877 (pthread_equal != NULL) && 878 (pthread_self != NULL) && 879 (pthread_cond_signal != NULL)) { 880 libxml_is_threaded = 1; 881 882 /* fprintf(stderr, "Running multithreaded\n"); */ 883 } else { 884 885 /* fprintf(stderr, "Running without multithread\n"); */ 886 libxml_is_threaded = 0; 887 } 888 } 889 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) 890 InitializeCriticalSection(&cleanup_helpers_cs); 891 #endif 892 } 893 894 /** 895 * xmlCleanupThreads: 896 * 897 * xmlCleanupThreads() is used to to cleanup all the thread related 898 * data of the libxml2 library once processing has ended. 899 * 900 * WARNING: if your application is multithreaded or has plugin support 901 * calling this may crash the application if another thread or 902 * a plugin is still using libxml2. It's sometimes very hard to 903 * guess if libxml2 is in use in the application, some libraries 904 * or plugins may use it without notice. In case of doubt abstain 905 * from calling this function or do it just before calling exit() 906 * to avoid leak reports from valgrind ! 907 */ 908 void 909 xmlCleanupThreads(void) 910 { 911 #ifdef DEBUG_THREADS 912 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n"); 913 #endif 914 #ifdef HAVE_PTHREAD_H 915 if ((libxml_is_threaded) && (pthread_key_delete != NULL)) 916 pthread_key_delete(globalkey); 917 once_control = once_control_init; 918 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) 919 if (globalkey != TLS_OUT_OF_INDEXES) { 920 xmlGlobalStateCleanupHelperParams *p; 921 922 EnterCriticalSection(&cleanup_helpers_cs); 923 p = cleanup_helpers_head; 924 while (p != NULL) { 925 xmlGlobalStateCleanupHelperParams *temp = p; 926 927 p = p->next; 928 xmlFreeGlobalState(temp->memory); 929 free(temp); 930 } 931 cleanup_helpers_head = 0; 932 LeaveCriticalSection(&cleanup_helpers_cs); 933 TlsFree(globalkey); 934 globalkey = TLS_OUT_OF_INDEXES; 935 } 936 DeleteCriticalSection(&cleanup_helpers_cs); 937 #endif 938 } 939 940 #ifdef LIBXML_THREAD_ENABLED 941 942 /** 943 * xmlOnceInit 944 * 945 * xmlOnceInit() is used to initialize the value of mainthread for use 946 * in other routines. This function should only be called using 947 * pthread_once() in association with the once_control variable to ensure 948 * that the function is only called once. See man pthread_once for more 949 * details. 950 */ 951 static void 952 xmlOnceInit(void) 953 { 954 #ifdef HAVE_PTHREAD_H 955 (void) pthread_key_create(&globalkey, xmlFreeGlobalState); 956 mainthread = pthread_self(); 957 __xmlInitializeDict(); 958 #elif defined(HAVE_WIN32_THREADS) 959 if (!run_once.done) { 960 if (InterlockedIncrement(&run_once.control) == 1) { 961 #if !defined(HAVE_COMPILER_TLS) 962 globalkey = TlsAlloc(); 963 #endif 964 mainthread = GetCurrentThreadId(); 965 __xmlInitializeDict(); 966 run_once.done = 1; 967 } else { 968 /* Another thread is working; give up our slice and 969 * wait until they're done. */ 970 while (!run_once.done) 971 Sleep(0); 972 } 973 } 974 #elif defined HAVE_BEOS_THREADS 975 if (atomic_add(&run_once_init, 1) == 0) { 976 globalkey = tls_allocate(); 977 tls_set(globalkey, NULL); 978 mainthread = find_thread(NULL); 979 __xmlInitializeDict(); 980 } else 981 atomic_add(&run_once_init, -1); 982 #endif 983 } 984 #endif 985 986 /** 987 * DllMain: 988 * @hinstDLL: handle to DLL instance 989 * @fdwReason: Reason code for entry 990 * @lpvReserved: generic pointer (depends upon reason code) 991 * 992 * Entry point for Windows library. It is being used to free thread-specific 993 * storage. 994 * 995 * Returns TRUE always 996 */ 997 #ifdef HAVE_PTHREAD_H 998 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) 999 #if defined(LIBXML_STATIC_FOR_DLL) 1000 BOOL XMLCALL 1001 xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 1002 #else 1003 BOOL WINAPI 1004 DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 1005 #endif 1006 { 1007 switch (fdwReason) { 1008 case DLL_THREAD_DETACH: 1009 if (globalkey != TLS_OUT_OF_INDEXES) { 1010 xmlGlobalState *globalval = NULL; 1011 xmlGlobalStateCleanupHelperParams *p = 1012 (xmlGlobalStateCleanupHelperParams *) 1013 TlsGetValue(globalkey); 1014 globalval = (xmlGlobalState *) (p ? p->memory : NULL); 1015 if (globalval) { 1016 xmlFreeGlobalState(globalval); 1017 TlsSetValue(globalkey, NULL); 1018 } 1019 if (p) { 1020 EnterCriticalSection(&cleanup_helpers_cs); 1021 if (p == cleanup_helpers_head) 1022 cleanup_helpers_head = p->next; 1023 else 1024 p->prev->next = p->next; 1025 if (p->next != NULL) 1026 p->next->prev = p->prev; 1027 LeaveCriticalSection(&cleanup_helpers_cs); 1028 free(p); 1029 } 1030 } 1031 break; 1032 } 1033 return TRUE; 1034 } 1035 #endif 1036 #define bottom_threads 1037 #include "elfgcchack.h" 1038