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