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