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