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 if (pthread_mutex_lock) 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 exit(); 503 #endif 504 } 505 #endif 506 } 507 508 void 509 __xmlGlobalInitMutexUnlock(void) 510 { 511 #ifdef HAVE_PTHREAD_H 512 if (pthread_mutex_unlock) 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 #ifdef HAVE_PTHREAD_H 533 #elif defined HAVE_WIN32_THREADS 534 if (global_init_lock != NULL) { 535 DeleteCriticalSection(global_init_lock); 536 free(global_init_lock); 537 global_init_lock = NULL; 538 } 539 #endif 540 } 541 542 /************************************************************************ 543 * * 544 * Per thread global state handling * 545 * * 546 ************************************************************************/ 547 548 #ifdef LIBXML_THREAD_ENABLED 549 #ifdef xmlLastError 550 #undef xmlLastError 551 #endif 552 553 /** 554 * xmlFreeGlobalState: 555 * @state: a thread global state 556 * 557 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL 558 * global state. It is is used here to reclaim memory resources. 559 */ 560 static void 561 xmlFreeGlobalState(void *state) 562 { 563 xmlGlobalState *gs = (xmlGlobalState *) state; 564 565 /* free any memory allocated in the thread's xmlLastError */ 566 xmlResetError(&(gs->xmlLastError)); 567 free(state); 568 } 569 570 /** 571 * xmlNewGlobalState: 572 * 573 * xmlNewGlobalState() allocates a global state. This structure is used to 574 * hold all data for use by a thread when supporting backwards compatibility 575 * of libxml2 to pre-thread-safe behaviour. 576 * 577 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error 578 */ 579 static xmlGlobalStatePtr 580 xmlNewGlobalState(void) 581 { 582 xmlGlobalState *gs; 583 584 gs = malloc(sizeof(xmlGlobalState)); 585 if (gs == NULL) { 586 xmlGenericError(xmlGenericErrorContext, 587 "xmlGetGlobalState: out of memory\n"); 588 return (NULL); 589 } 590 591 memset(gs, 0, sizeof(xmlGlobalState)); 592 xmlInitializeGlobalState(gs); 593 return (gs); 594 } 595 #endif /* LIBXML_THREAD_ENABLED */ 596 597 #ifdef HAVE_PTHREAD_H 598 #elif defined HAVE_WIN32_THREADS 599 #if !defined(HAVE_COMPILER_TLS) 600 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) 601 typedef struct _xmlGlobalStateCleanupHelperParams { 602 HANDLE thread; 603 void *memory; 604 } xmlGlobalStateCleanupHelperParams; 605 606 static void XMLCDECL 607 xmlGlobalStateCleanupHelper(void *p) 608 { 609 xmlGlobalStateCleanupHelperParams *params = 610 (xmlGlobalStateCleanupHelperParams *) p; 611 WaitForSingleObject(params->thread, INFINITE); 612 CloseHandle(params->thread); 613 xmlFreeGlobalState(params->memory); 614 free(params); 615 _endthread(); 616 } 617 #else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */ 618 619 typedef struct _xmlGlobalStateCleanupHelperParams { 620 void *memory; 621 struct _xmlGlobalStateCleanupHelperParams *prev; 622 struct _xmlGlobalStateCleanupHelperParams *next; 623 } xmlGlobalStateCleanupHelperParams; 624 625 static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL; 626 static CRITICAL_SECTION cleanup_helpers_cs; 627 628 #endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */ 629 #endif /* HAVE_COMPILER_TLS */ 630 #endif /* HAVE_WIN32_THREADS */ 631 632 #if defined HAVE_BEOS_THREADS 633 634 /** 635 * xmlGlobalStateCleanup: 636 * @data: unused parameter 637 * 638 * Used for Beos only 639 */ 640 void 641 xmlGlobalStateCleanup(void *data) 642 { 643 void *globalval = tls_get(globalkey); 644 645 if (globalval != NULL) 646 xmlFreeGlobalState(globalval); 647 } 648 #endif 649 650 /** 651 * xmlGetGlobalState: 652 * 653 * xmlGetGlobalState() is called to retrieve the global state for a thread. 654 * 655 * Returns the thread global state or NULL in case of error 656 */ 657 xmlGlobalStatePtr 658 xmlGetGlobalState(void) 659 { 660 #ifdef HAVE_PTHREAD_H 661 xmlGlobalState *globalval; 662 663 if (libxml_is_threaded == 0) 664 return (NULL); 665 666 pthread_once(&once_control, xmlOnceInit); 667 668 if ((globalval = (xmlGlobalState *) 669 pthread_getspecific(globalkey)) == NULL) { 670 xmlGlobalState *tsd = xmlNewGlobalState(); 671 if (tsd == NULL) 672 return(NULL); 673 674 pthread_setspecific(globalkey, tsd); 675 return (tsd); 676 } 677 return (globalval); 678 #elif defined HAVE_WIN32_THREADS 679 #if defined(HAVE_COMPILER_TLS) 680 if (!tlstate_inited) { 681 tlstate_inited = 1; 682 xmlInitializeGlobalState(&tlstate); 683 } 684 return &tlstate; 685 #else /* HAVE_COMPILER_TLS */ 686 xmlGlobalState *globalval; 687 xmlGlobalStateCleanupHelperParams *p; 688 689 xmlOnceInit(); 690 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) 691 globalval = (xmlGlobalState *) TlsGetValue(globalkey); 692 #else 693 p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey); 694 globalval = (xmlGlobalState *) (p ? p->memory : NULL); 695 #endif 696 if (globalval == NULL) { 697 xmlGlobalState *tsd = xmlNewGlobalState(); 698 699 if (tsd == NULL) 700 return(NULL); 701 p = (xmlGlobalStateCleanupHelperParams *) 702 malloc(sizeof(xmlGlobalStateCleanupHelperParams)); 703 if (p == NULL) { 704 xmlGenericError(xmlGenericErrorContext, 705 "xmlGetGlobalState: out of memory\n"); 706 xmlFreeGlobalState(tsd); 707 return(NULL); 708 } 709 p->memory = tsd; 710 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) 711 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), 712 GetCurrentProcess(), &p->thread, 0, TRUE, 713 DUPLICATE_SAME_ACCESS); 714 TlsSetValue(globalkey, tsd); 715 _beginthread(xmlGlobalStateCleanupHelper, 0, p); 716 #else 717 EnterCriticalSection(&cleanup_helpers_cs); 718 if (cleanup_helpers_head != NULL) { 719 cleanup_helpers_head->prev = p; 720 } 721 p->next = cleanup_helpers_head; 722 p->prev = NULL; 723 cleanup_helpers_head = p; 724 TlsSetValue(globalkey, p); 725 LeaveCriticalSection(&cleanup_helpers_cs); 726 #endif 727 728 return (tsd); 729 } 730 return (globalval); 731 #endif /* HAVE_COMPILER_TLS */ 732 #elif defined HAVE_BEOS_THREADS 733 xmlGlobalState *globalval; 734 735 xmlOnceInit(); 736 737 if ((globalval = (xmlGlobalState *) tls_get(globalkey)) == NULL) { 738 xmlGlobalState *tsd = xmlNewGlobalState(); 739 if (tsd == NULL) 740 return (NULL); 741 742 tls_set(globalkey, tsd); 743 on_exit_thread(xmlGlobalStateCleanup, NULL); 744 return (tsd); 745 } 746 return (globalval); 747 #else 748 return (NULL); 749 #endif 750 } 751 752 /************************************************************************ 753 * * 754 * Library wide thread interfaces * 755 * * 756 ************************************************************************/ 757 758 /** 759 * xmlGetThreadId: 760 * 761 * xmlGetThreadId() find the current thread ID number 762 * Note that this is likely to be broken on some platforms using pthreads 763 * as the specification doesn't mandate pthread_t to be an integer type 764 * 765 * Returns the current thread ID number 766 */ 767 int 768 xmlGetThreadId(void) 769 { 770 #ifdef HAVE_PTHREAD_H 771 pthread_t id; 772 int ret; 773 774 if (libxml_is_threaded == 0) 775 return (0); 776 id = pthread_self(); 777 /* horrible but preserves compat, see warning above */ 778 memcpy(&ret, &id, sizeof(ret)); 779 return (ret); 780 #elif defined HAVE_WIN32_THREADS 781 return GetCurrentThreadId(); 782 #elif defined HAVE_BEOS_THREADS 783 return find_thread(NULL); 784 #else 785 return ((int) 0); 786 #endif 787 } 788 789 /** 790 * xmlIsMainThread: 791 * 792 * xmlIsMainThread() check whether the current thread is the main thread. 793 * 794 * Returns 1 if the current thread is the main thread, 0 otherwise 795 */ 796 int 797 xmlIsMainThread(void) 798 { 799 #ifdef HAVE_PTHREAD_H 800 if (libxml_is_threaded == -1) 801 xmlInitThreads(); 802 if (libxml_is_threaded == 0) 803 return (1); 804 pthread_once(&once_control, xmlOnceInit); 805 #elif defined HAVE_WIN32_THREADS 806 xmlOnceInit(); 807 #elif defined HAVE_BEOS_THREADS 808 xmlOnceInit(); 809 #endif 810 811 #ifdef DEBUG_THREADS 812 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n"); 813 #endif 814 #ifdef HAVE_PTHREAD_H 815 return (pthread_equal(mainthread,pthread_self())); 816 #elif defined HAVE_WIN32_THREADS 817 return (mainthread == GetCurrentThreadId()); 818 #elif defined HAVE_BEOS_THREADS 819 return (mainthread == find_thread(NULL)); 820 #else 821 return (1); 822 #endif 823 } 824 825 /** 826 * xmlLockLibrary: 827 * 828 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2 829 * library. 830 */ 831 void 832 xmlLockLibrary(void) 833 { 834 #ifdef DEBUG_THREADS 835 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n"); 836 #endif 837 xmlRMutexLock(xmlLibraryLock); 838 } 839 840 /** 841 * xmlUnlockLibrary: 842 * 843 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2 844 * library. 845 */ 846 void 847 xmlUnlockLibrary(void) 848 { 849 #ifdef DEBUG_THREADS 850 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n"); 851 #endif 852 xmlRMutexUnlock(xmlLibraryLock); 853 } 854 855 /** 856 * xmlInitThreads: 857 * 858 * xmlInitThreads() is used to to initialize all the thread related 859 * data of the libxml2 library. 860 */ 861 void 862 xmlInitThreads(void) 863 { 864 #ifdef HAVE_PTHREAD_H 865 if (libxml_is_threaded == -1) { 866 if ((pthread_once != NULL) && 867 (pthread_getspecific != NULL) && 868 (pthread_setspecific != NULL) && 869 (pthread_key_create != NULL) && 870 (pthread_key_delete != NULL) && 871 (pthread_mutex_init != NULL) && 872 (pthread_mutex_destroy != NULL) && 873 (pthread_mutex_lock != NULL) && 874 (pthread_mutex_unlock != NULL) && 875 (pthread_cond_init != NULL) && 876 (pthread_cond_destroy != NULL) && 877 (pthread_cond_wait != NULL) && 878 (pthread_equal != NULL) && 879 (pthread_self != NULL) && 880 (pthread_cond_signal != NULL)) { 881 libxml_is_threaded = 1; 882 883 /* fprintf(stderr, "Running multithreaded\n"); */ 884 } else { 885 886 /* fprintf(stderr, "Running without multithread\n"); */ 887 libxml_is_threaded = 0; 888 } 889 } 890 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) 891 InitializeCriticalSection(&cleanup_helpers_cs); 892 #endif 893 } 894 895 /** 896 * xmlCleanupThreads: 897 * 898 * xmlCleanupThreads() is used to to cleanup all the thread related 899 * data of the libxml2 library once processing has ended. 900 * 901 * WARNING: if your application is multithreaded or has plugin support 902 * calling this may crash the application if another thread or 903 * a plugin is still using libxml2. It's sometimes very hard to 904 * guess if libxml2 is in use in the application, some libraries 905 * or plugins may use it without notice. In case of doubt abstain 906 * from calling this function or do it just before calling exit() 907 * to avoid leak reports from valgrind ! 908 */ 909 void 910 xmlCleanupThreads(void) 911 { 912 #ifdef DEBUG_THREADS 913 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n"); 914 #endif 915 #ifdef HAVE_PTHREAD_H 916 if ((libxml_is_threaded) && (pthread_key_delete != NULL)) 917 pthread_key_delete(globalkey); 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 #elif defined(HAVE_WIN32_THREADS) 958 if (!run_once.done) { 959 if (InterlockedIncrement(&run_once.control) == 1) { 960 #if !defined(HAVE_COMPILER_TLS) 961 globalkey = TlsAlloc(); 962 #endif 963 mainthread = GetCurrentThreadId(); 964 run_once.done = 1; 965 } else { 966 /* Another thread is working; give up our slice and 967 * wait until they're done. */ 968 while (!run_once.done) 969 Sleep(0); 970 } 971 } 972 #elif defined HAVE_BEOS_THREADS 973 if (atomic_add(&run_once_init, 1) == 0) { 974 globalkey = tls_allocate(); 975 tls_set(globalkey, NULL); 976 mainthread = find_thread(NULL); 977 } else 978 atomic_add(&run_once_init, -1); 979 #endif 980 } 981 #endif 982 983 /** 984 * DllMain: 985 * @hinstDLL: handle to DLL instance 986 * @fdwReason: Reason code for entry 987 * @lpvReserved: generic pointer (depends upon reason code) 988 * 989 * Entry point for Windows library. It is being used to free thread-specific 990 * storage. 991 * 992 * Returns TRUE always 993 */ 994 #ifdef HAVE_PTHREAD_H 995 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) 996 #if defined(LIBXML_STATIC_FOR_DLL) 997 BOOL XMLCALL 998 xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 999 #else 1000 BOOL WINAPI 1001 DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 1002 #endif 1003 { 1004 switch (fdwReason) { 1005 case DLL_THREAD_DETACH: 1006 if (globalkey != TLS_OUT_OF_INDEXES) { 1007 xmlGlobalState *globalval = NULL; 1008 xmlGlobalStateCleanupHelperParams *p = 1009 (xmlGlobalStateCleanupHelperParams *) 1010 TlsGetValue(globalkey); 1011 globalval = (xmlGlobalState *) (p ? p->memory : NULL); 1012 if (globalval) { 1013 xmlFreeGlobalState(globalval); 1014 TlsSetValue(globalkey, NULL); 1015 } 1016 if (p) { 1017 EnterCriticalSection(&cleanup_helpers_cs); 1018 if (p == cleanup_helpers_head) 1019 cleanup_helpers_head = p->next; 1020 else 1021 p->prev->next = p->next; 1022 if (p->next != NULL) 1023 p->next->prev = p->prev; 1024 LeaveCriticalSection(&cleanup_helpers_cs); 1025 free(p); 1026 } 1027 } 1028 break; 1029 } 1030 return TRUE; 1031 } 1032 #endif 1033 #define bottom_threads 1034 #include "elfgcchack.h" 1035