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 53static 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 77static 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 crazyness 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 */ 92struct _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 */ 108struct _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 134static pthread_key_t globalkey; 135static pthread_t mainthread; 136static pthread_once_t once_control = PTHREAD_ONCE_INIT; 137static pthread_once_t once_control_init = PTHREAD_ONCE_INIT; 138static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER; 139#elif defined HAVE_WIN32_THREADS 140#if defined(HAVE_COMPILER_TLS) 141static __declspec(thread) xmlGlobalState tlstate; 142static __declspec(thread) int tlstate_inited = 0; 143#else /* HAVE_COMPILER_TLS */ 144static DWORD globalkey = TLS_OUT_OF_INDEXES; 145#endif /* HAVE_COMPILER_TLS */ 146static DWORD mainthread; 147static struct { 148 DWORD done; 149 LONG control; 150} run_once = { 0, 0}; 151static volatile LPCRITICAL_SECTION global_init_lock = NULL; 152 153/* endif HAVE_WIN32_THREADS */ 154#elif defined HAVE_BEOS_THREADS 155int32 globalkey = 0; 156thread_id mainthread = 0; 157int32 run_once_init = 0; 158static int32 global_init_lock = -1; 159static vint32 global_init_count = 0; 160#endif 161 162static xmlRMutexPtr xmlLibraryLock = NULL; 163 164#ifdef LIBXML_THREAD_ENABLED 165static 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 */ 176xmlMutexPtr 177xmlNewMutex(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 */ 205void 206xmlFreeMutex(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 */ 228void 229xmlMutexLock(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 aquire 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 */ 256void 257xmlMutexUnlock(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 */ 284xmlRMutexPtr 285xmlNewRMutex(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 */ 318void 319xmlFreeRMutex(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 */ 342void 343xmlRMutexLock(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 */ 387void 388xmlRMutexUnlock(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 */ 426void 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 501void 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 */ 525void 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 */ 556static void 557xmlFreeGlobalState(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 */ 575static xmlGlobalStatePtr 576xmlNewGlobalState(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) 597typedef struct _xmlGlobalStateCleanupHelperParams { 598 HANDLE thread; 599 void *memory; 600} xmlGlobalStateCleanupHelperParams; 601 602static void XMLCDECL 603xmlGlobalStateCleanupHelper(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 615typedef struct _xmlGlobalStateCleanupHelperParams { 616 void *memory; 617 struct _xmlGlobalStateCleanupHelperParams *prev; 618 struct _xmlGlobalStateCleanupHelperParams *next; 619} xmlGlobalStateCleanupHelperParams; 620 621static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL; 622static 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 */ 636void 637xmlGlobalStateCleanup(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 */ 653xmlGlobalStatePtr 654xmlGetGlobalState(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 */ 763int 764xmlGetThreadId(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 */ 792int 793xmlIsMainThread(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 */ 827void 828xmlLockLibrary(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 */ 842void 843xmlUnlockLibrary(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 */ 857void 858xmlInitThreads(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 */ 907void 908xmlCleanupThreads(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 */ 950static void 951xmlOnceInit(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) 999int XMLCALL 1000xmlDllMain(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 1008XMLPUBFUN BOOL WINAPI 1009DllMain (HINSTANCE hinstDLL, 1010 DWORD fdwReason, 1011 LPVOID lpvReserved); 1012 1013BOOL WINAPI 1014DllMain(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