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