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