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; 142#elif defined HAVE_WIN32_THREADS 143#if defined(HAVE_COMPILER_TLS) 144static __declspec(thread) xmlGlobalState tlstate; 145static __declspec(thread) int tlstate_inited = 0; 146#else /* HAVE_COMPILER_TLS */ 147static DWORD globalkey = TLS_OUT_OF_INDEXES; 148#endif /* HAVE_COMPILER_TLS */ 149static DWORD mainthread; 150static struct 151{ 152 DWORD done; 153 DWORD control; 154} run_once = { 0, 0 }; 155/* endif HAVE_WIN32_THREADS */ 156#elif defined HAVE_BEOS_THREADS 157int32 globalkey = 0; 158thread_id mainthread = 0; 159int32 run_once_init = 0; 160#endif 161 162static xmlRMutexPtr xmlLibraryLock = NULL; 163#ifdef LIBXML_THREAD_ENABLED 164static void xmlOnceInit(void); 165#endif 166 167/** 168 * xmlNewMutex: 169 * 170 * xmlNewMutex() is used to allocate a libxml2 token struct for use in 171 * synchronizing access to data. 172 * 173 * Returns a new simple mutex pointer or NULL in case of error 174 */ 175xmlMutexPtr 176xmlNewMutex(void) 177{ 178 xmlMutexPtr tok; 179 180 if ((tok = malloc(sizeof(xmlMutex))) == NULL) 181 return (NULL); 182#ifdef HAVE_PTHREAD_H 183 if (libxml_is_threaded != 0) 184 pthread_mutex_init(&tok->lock, NULL); 185#elif defined HAVE_WIN32_THREADS 186 tok->mutex = CreateMutex(NULL, FALSE, NULL); 187#elif defined HAVE_BEOS_THREADS 188 if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) { 189 free(tok); 190 return NULL; 191 } 192 tok->tid = -1; 193#endif 194 return (tok); 195} 196 197/** 198 * xmlFreeMutex: 199 * @tok: the simple mutex 200 * 201 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token 202 * struct. 203 */ 204void 205xmlFreeMutex(xmlMutexPtr tok) 206{ 207 if (tok == NULL) return; 208 209#ifdef HAVE_PTHREAD_H 210 if (libxml_is_threaded != 0) 211 pthread_mutex_destroy(&tok->lock); 212#elif defined HAVE_WIN32_THREADS 213 CloseHandle(tok->mutex); 214#elif defined HAVE_BEOS_THREADS 215 delete_sem(tok->sem); 216#endif 217 free(tok); 218} 219 220/** 221 * xmlMutexLock: 222 * @tok: the simple mutex 223 * 224 * xmlMutexLock() is used to lock a libxml2 token. 225 */ 226void 227xmlMutexLock(xmlMutexPtr tok) 228{ 229 if (tok == NULL) 230 return; 231#ifdef HAVE_PTHREAD_H 232 if (libxml_is_threaded != 0) 233 pthread_mutex_lock(&tok->lock); 234#elif defined HAVE_WIN32_THREADS 235 WaitForSingleObject(tok->mutex, INFINITE); 236#elif defined HAVE_BEOS_THREADS 237 if (acquire_sem(tok->sem) != B_NO_ERROR) { 238#ifdef DEBUG_THREADS 239 xmlGenericError(xmlGenericErrorContext, "xmlMutexLock():BeOS:Couldn't aquire semaphore\n"); 240 exit(); 241#endif 242 } 243 tok->tid = find_thread(NULL); 244#endif 245 246} 247 248/** 249 * xmlMutexUnlock: 250 * @tok: the simple mutex 251 * 252 * xmlMutexUnlock() is used to unlock a libxml2 token. 253 */ 254void 255xmlMutexUnlock(xmlMutexPtr tok) 256{ 257 if (tok == NULL) 258 return; 259#ifdef HAVE_PTHREAD_H 260 if (libxml_is_threaded != 0) 261 pthread_mutex_unlock(&tok->lock); 262#elif defined HAVE_WIN32_THREADS 263 ReleaseMutex(tok->mutex); 264#elif defined HAVE_BEOS_THREADS 265 if (tok->tid == find_thread(NULL)) { 266 tok->tid = -1; 267 release_sem(tok->sem); 268 } 269#endif 270} 271 272/** 273 * xmlNewRMutex: 274 * 275 * xmlRNewMutex() is used to allocate a reentrant mutex for use in 276 * synchronizing access to data. token_r is a re-entrant lock and thus useful 277 * for synchronizing access to data structures that may be manipulated in a 278 * recursive fashion. 279 * 280 * Returns the new reentrant mutex pointer or NULL in case of error 281 */ 282xmlRMutexPtr 283xmlNewRMutex(void) 284{ 285 xmlRMutexPtr tok; 286 287 if ((tok = malloc(sizeof(xmlRMutex))) == NULL) 288 return (NULL); 289#ifdef HAVE_PTHREAD_H 290 if (libxml_is_threaded != 0) { 291 pthread_mutex_init(&tok->lock, NULL); 292 tok->held = 0; 293 tok->waiters = 0; 294 pthread_cond_init(&tok->cv, NULL); 295 } 296#elif defined HAVE_WIN32_THREADS 297 InitializeCriticalSection(&tok->cs); 298 tok->count = 0; 299#elif defined HAVE_BEOS_THREADS 300 if ((tok->lock = xmlNewMutex()) == NULL) { 301 free(tok); 302 return NULL; 303 } 304 tok->count = 0; 305#endif 306 return (tok); 307} 308 309/** 310 * xmlFreeRMutex: 311 * @tok: the reentrant mutex 312 * 313 * xmlRFreeMutex() is used to reclaim resources associated with a 314 * reentrant mutex. 315 */ 316void 317xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED) 318{ 319 if (tok == NULL) 320 return; 321#ifdef HAVE_PTHREAD_H 322 if (libxml_is_threaded != 0) 323 pthread_mutex_destroy(&tok->lock); 324#elif defined HAVE_WIN32_THREADS 325 DeleteCriticalSection(&tok->cs); 326#elif defined HAVE_BEOS_THREADS 327 xmlFreeMutex(tok->lock); 328#endif 329 free(tok); 330} 331 332/** 333 * xmlRMutexLock: 334 * @tok: the reentrant mutex 335 * 336 * xmlRMutexLock() is used to lock a libxml2 token_r. 337 */ 338void 339xmlRMutexLock(xmlRMutexPtr tok) 340{ 341 if (tok == NULL) 342 return; 343#ifdef HAVE_PTHREAD_H 344 if (libxml_is_threaded == 0) 345 return; 346 347 pthread_mutex_lock(&tok->lock); 348 if (tok->held) { 349 if (pthread_equal(tok->tid, pthread_self())) { 350 tok->held++; 351 pthread_mutex_unlock(&tok->lock); 352 return; 353 } else { 354 tok->waiters++; 355 while (tok->held) 356 pthread_cond_wait(&tok->cv, &tok->lock); 357 tok->waiters--; 358 } 359 } 360 tok->tid = pthread_self(); 361 tok->held = 1; 362 pthread_mutex_unlock(&tok->lock); 363#elif defined HAVE_WIN32_THREADS 364 EnterCriticalSection(&tok->cs); 365 ++tok->count; 366#elif defined HAVE_BEOS_THREADS 367 if (tok->lock->tid == find_thread(NULL)) { 368 tok->count++; 369 return; 370 } else { 371 xmlMutexLock(tok->lock); 372 tok->count = 1; 373 } 374#endif 375} 376 377/** 378 * xmlRMutexUnlock: 379 * @tok: the reentrant mutex 380 * 381 * xmlRMutexUnlock() is used to unlock a libxml2 token_r. 382 */ 383void 384xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED) 385{ 386 if (tok == NULL) 387 return; 388#ifdef HAVE_PTHREAD_H 389 if (libxml_is_threaded == 0) 390 return; 391 392 pthread_mutex_lock(&tok->lock); 393 tok->held--; 394 if (tok->held == 0) { 395 if (tok->waiters) 396 pthread_cond_signal(&tok->cv); 397 tok->tid = 0; 398 } 399 pthread_mutex_unlock(&tok->lock); 400#elif defined HAVE_WIN32_THREADS 401 if (!--tok->count) 402 LeaveCriticalSection(&tok->cs); 403#elif defined HAVE_BEOS_THREADS 404 if (tok->lock->tid == find_thread(NULL)) { 405 tok->count--; 406 if (tok->count == 0) { 407 xmlMutexUnlock(tok->lock); 408 } 409 return; 410 } 411#endif 412} 413 414/************************************************************************ 415 * * 416 * Per thread global state handling * 417 * * 418 ************************************************************************/ 419 420#ifdef LIBXML_THREAD_ENABLED 421#ifdef xmlLastError 422#undef xmlLastError 423#endif 424/** 425 * xmlFreeGlobalState: 426 * @state: a thread global state 427 * 428 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL 429 * global state. It is is used here to reclaim memory resources. 430 */ 431static void 432xmlFreeGlobalState(void *state) 433{ 434 xmlGlobalState *gs = (xmlGlobalState *) state; 435 436 /* free any memory allocated in the thread's xmlLastError */ 437 xmlResetError(&(gs->xmlLastError)); 438 free(state); 439} 440 441/** 442 * xmlNewGlobalState: 443 * 444 * xmlNewGlobalState() allocates a global state. This structure is used to 445 * hold all data for use by a thread when supporting backwards compatibility 446 * of libxml2 to pre-thread-safe behaviour. 447 * 448 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error 449 */ 450static xmlGlobalStatePtr 451xmlNewGlobalState(void) 452{ 453 xmlGlobalState *gs; 454 455 gs = malloc(sizeof(xmlGlobalState)); 456 if (gs == NULL) 457 return(NULL); 458 459 memset(gs, 0, sizeof(xmlGlobalState)); 460 xmlInitializeGlobalState(gs); 461 return (gs); 462} 463#endif /* LIBXML_THREAD_ENABLED */ 464 465 466#ifdef HAVE_WIN32_THREADS 467#if !defined(HAVE_COMPILER_TLS) 468#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) 469typedef struct _xmlGlobalStateCleanupHelperParams 470{ 471 HANDLE thread; 472 void *memory; 473} xmlGlobalStateCleanupHelperParams; 474 475static void XMLCDECL xmlGlobalStateCleanupHelper (void *p) 476{ 477 xmlGlobalStateCleanupHelperParams *params = (xmlGlobalStateCleanupHelperParams *) p; 478 WaitForSingleObject(params->thread, INFINITE); 479 CloseHandle(params->thread); 480 xmlFreeGlobalState(params->memory); 481 free(params); 482 _endthread(); 483} 484#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */ 485 486typedef struct _xmlGlobalStateCleanupHelperParams 487{ 488 void *memory; 489 struct _xmlGlobalStateCleanupHelperParams * prev; 490 struct _xmlGlobalStateCleanupHelperParams * next; 491} xmlGlobalStateCleanupHelperParams; 492 493static xmlGlobalStateCleanupHelperParams * cleanup_helpers_head = NULL; 494static CRITICAL_SECTION cleanup_helpers_cs; 495 496#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */ 497#endif /* HAVE_COMPILER_TLS */ 498#endif /* HAVE_WIN32_THREADS */ 499 500#if defined HAVE_BEOS_THREADS 501/** 502 * xmlGlobalStateCleanup: 503 * @data: unused parameter 504 * 505 * Used for Beos only 506 */ 507void xmlGlobalStateCleanup(void *data) 508{ 509 void *globalval = tls_get(globalkey); 510 if (globalval != NULL) 511 xmlFreeGlobalState(globalval); 512} 513#endif 514 515/** 516 * xmlGetGlobalState: 517 * 518 * xmlGetGlobalState() is called to retrieve the global state for a thread. 519 * 520 * Returns the thread global state or NULL in case of error 521 */ 522xmlGlobalStatePtr 523xmlGetGlobalState(void) 524{ 525#ifdef HAVE_PTHREAD_H 526 xmlGlobalState *globalval; 527 528 if (libxml_is_threaded == 0) 529 return(NULL); 530 531 pthread_once(&once_control, xmlOnceInit); 532 533 if ((globalval = (xmlGlobalState *) 534 pthread_getspecific(globalkey)) == NULL) { 535 xmlGlobalState *tsd = xmlNewGlobalState(); 536 537 pthread_setspecific(globalkey, tsd); 538 return (tsd); 539 } 540 return (globalval); 541#elif defined HAVE_WIN32_THREADS 542#if defined(HAVE_COMPILER_TLS) 543 if (!tlstate_inited) { 544 tlstate_inited = 1; 545 xmlInitializeGlobalState(&tlstate); 546 } 547 return &tlstate; 548#else /* HAVE_COMPILER_TLS */ 549 xmlGlobalState *globalval; 550 xmlGlobalStateCleanupHelperParams * p; 551 552 xmlOnceInit(); 553#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) 554 globalval = (xmlGlobalState *)TlsGetValue(globalkey); 555#else 556 p = (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey); 557 globalval = (xmlGlobalState *)(p ? p->memory : NULL); 558#endif 559 if (globalval == NULL) { 560 xmlGlobalState *tsd = xmlNewGlobalState(); 561 p = (xmlGlobalStateCleanupHelperParams *) malloc(sizeof(xmlGlobalStateCleanupHelperParams)); 562 p->memory = tsd; 563#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) 564 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), 565 GetCurrentProcess(), &p->thread, 0, TRUE, DUPLICATE_SAME_ACCESS); 566 TlsSetValue(globalkey, tsd); 567 _beginthread(xmlGlobalStateCleanupHelper, 0, p); 568#else 569 EnterCriticalSection(&cleanup_helpers_cs); 570 if (cleanup_helpers_head != NULL) { 571 cleanup_helpers_head->prev = p; 572 } 573 p->next = cleanup_helpers_head; 574 p->prev = NULL; 575 cleanup_helpers_head = p; 576 TlsSetValue(globalkey, p); 577 LeaveCriticalSection(&cleanup_helpers_cs); 578#endif 579 580 return (tsd); 581 } 582 return (globalval); 583#endif /* HAVE_COMPILER_TLS */ 584#elif defined HAVE_BEOS_THREADS 585 xmlGlobalState *globalval; 586 587 xmlOnceInit(); 588 589 if ((globalval = (xmlGlobalState *) 590 tls_get(globalkey)) == NULL) { 591 xmlGlobalState *tsd = xmlNewGlobalState(); 592 593 tls_set(globalkey, tsd); 594 on_exit_thread(xmlGlobalStateCleanup, NULL); 595 return (tsd); 596 } 597 return (globalval); 598#else 599 return(NULL); 600#endif 601} 602 603/************************************************************************ 604 * * 605 * Library wide thread interfaces * 606 * * 607 ************************************************************************/ 608 609/** 610 * xmlGetThreadId: 611 * 612 * xmlGetThreadId() find the current thread ID number 613 * 614 * Returns the current thread ID number 615 */ 616int 617xmlGetThreadId(void) 618{ 619#ifdef HAVE_PTHREAD_H 620 if (libxml_is_threaded == 0) 621 return(0); 622 return((int) pthread_self()); 623#elif defined HAVE_WIN32_THREADS 624 return GetCurrentThreadId(); 625#elif defined HAVE_BEOS_THREADS 626 return find_thread(NULL); 627#else 628 return((int) 0); 629#endif 630} 631 632/** 633 * xmlIsMainThread: 634 * 635 * xmlIsMainThread() check whether the current thread is the main thread. 636 * 637 * Returns 1 if the current thread is the main thread, 0 otherwise 638 */ 639int 640xmlIsMainThread(void) 641{ 642#ifdef HAVE_PTHREAD_H 643 if (libxml_is_threaded == -1) 644 xmlInitThreads(); 645 if (libxml_is_threaded == 0) 646 return(1); 647 pthread_once(&once_control, xmlOnceInit); 648#elif defined HAVE_WIN32_THREADS 649 xmlOnceInit (); 650#elif defined HAVE_BEOS_THREADS 651 xmlOnceInit(); 652#endif 653 654#ifdef DEBUG_THREADS 655 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n"); 656#endif 657#ifdef HAVE_PTHREAD_H 658 return(mainthread == pthread_self()); 659#elif defined HAVE_WIN32_THREADS 660 return(mainthread == GetCurrentThreadId ()); 661#elif defined HAVE_BEOS_THREADS 662 return(mainthread == find_thread(NULL)); 663#else 664 return(1); 665#endif 666} 667 668/** 669 * xmlLockLibrary: 670 * 671 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2 672 * library. 673 */ 674void 675xmlLockLibrary(void) 676{ 677#ifdef DEBUG_THREADS 678 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n"); 679#endif 680 xmlRMutexLock(xmlLibraryLock); 681} 682 683/** 684 * xmlUnlockLibrary: 685 * 686 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2 687 * library. 688 */ 689void 690xmlUnlockLibrary(void) 691{ 692#ifdef DEBUG_THREADS 693 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n"); 694#endif 695 xmlRMutexUnlock(xmlLibraryLock); 696} 697 698/** 699 * xmlInitThreads: 700 * 701 * xmlInitThreads() is used to to initialize all the thread related 702 * data of the libxml2 library. 703 */ 704void 705xmlInitThreads(void) 706{ 707#ifdef DEBUG_THREADS 708 xmlGenericError(xmlGenericErrorContext, "xmlInitThreads()\n"); 709#endif 710#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) 711 InitializeCriticalSection(&cleanup_helpers_cs); 712#endif 713#ifdef HAVE_PTHREAD_H 714 if (libxml_is_threaded == -1) { 715 if ((pthread_once != NULL) && 716 (pthread_getspecific != NULL) && 717 (pthread_setspecific != NULL) && 718 (pthread_key_create != NULL) && 719 (pthread_mutex_init != NULL) && 720 (pthread_mutex_destroy != NULL) && 721 (pthread_mutex_lock != NULL) && 722 (pthread_mutex_unlock != NULL) && 723 (pthread_cond_init != NULL) && 724 (pthread_equal != NULL) && 725 (pthread_self != NULL) && 726 (pthread_key_create != NULL) && 727 (pthread_cond_signal != NULL)) { 728 libxml_is_threaded = 1; 729/* fprintf(stderr, "Running multithreaded\n"); */ 730 } else { 731/* fprintf(stderr, "Running without multithread\n"); */ 732 libxml_is_threaded = 0; 733 } 734 } 735#endif 736} 737 738/** 739 * xmlCleanupThreads: 740 * 741 * xmlCleanupThreads() is used to to cleanup all the thread related 742 * data of the libxml2 library once processing has ended. 743 */ 744void 745xmlCleanupThreads(void) 746{ 747#ifdef DEBUG_THREADS 748 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n"); 749#endif 750#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) 751 if (globalkey != TLS_OUT_OF_INDEXES) { 752 xmlGlobalStateCleanupHelperParams * p; 753 EnterCriticalSection(&cleanup_helpers_cs); 754 p = cleanup_helpers_head; 755 while (p != NULL) { 756 xmlGlobalStateCleanupHelperParams * temp = p; 757 p = p->next; 758 xmlFreeGlobalState(temp->memory); 759 free(temp); 760 } 761 cleanup_helpers_head = 0; 762 LeaveCriticalSection(&cleanup_helpers_cs); 763 TlsFree(globalkey); 764 globalkey = TLS_OUT_OF_INDEXES; 765 } 766 DeleteCriticalSection(&cleanup_helpers_cs); 767#endif 768} 769 770#ifdef LIBXML_THREAD_ENABLED 771/** 772 * xmlOnceInit 773 * 774 * xmlOnceInit() is used to initialize the value of mainthread for use 775 * in other routines. This function should only be called using 776 * pthread_once() in association with the once_control variable to ensure 777 * that the function is only called once. See man pthread_once for more 778 * details. 779 */ 780static void 781xmlOnceInit(void) { 782#ifdef HAVE_PTHREAD_H 783 (void) pthread_key_create(&globalkey, xmlFreeGlobalState); 784 mainthread = pthread_self(); 785#endif 786 787#if defined(HAVE_WIN32_THREADS) 788 if (!run_once.done) { 789 if (InterlockedIncrement(&run_once.control) == 1) 790 { 791#if !defined(HAVE_COMPILER_TLS) 792 globalkey = TlsAlloc(); 793#endif 794 mainthread = GetCurrentThreadId(); 795 run_once.done = 1; 796 } 797 else { 798 /* Another thread is working; give up our slice and 799 * wait until they're done. */ 800 while (!run_once.done) 801 Sleep(0); 802 } 803 } 804#endif 805 806#ifdef HAVE_BEOS_THREADS 807 if (atomic_add(&run_once_init, 1) == 0) { 808 globalkey = tls_allocate(); 809 tls_set(globalkey, NULL); 810 mainthread = find_thread(NULL); 811 } else 812 atomic_add(&run_once_init, -1); 813#endif 814} 815#endif 816 817/** 818 * DllMain: 819 * @hinstDLL: handle to DLL instance 820 * @fdwReason: Reason code for entry 821 * @lpvReserved: generic pointer (depends upon reason code) 822 * 823 * Entry point for Windows library. It is being used to free thread-specific 824 * storage. 825 * 826 * Returns TRUE always 827 */ 828#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) 829#if defined(LIBXML_STATIC_FOR_DLL) 830BOOL WINAPI xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 831#else 832BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 833#endif 834{ 835 switch(fdwReason) { 836 case DLL_THREAD_DETACH: 837 if (globalkey != TLS_OUT_OF_INDEXES) { 838 xmlGlobalState *globalval = NULL; 839 xmlGlobalStateCleanupHelperParams * p = 840 (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey); 841 globalval = (xmlGlobalState *)(p ? p->memory : NULL); 842 if (globalval) { 843 xmlFreeGlobalState(globalval); 844 TlsSetValue(globalkey,NULL); 845 } 846 if (p) 847 { 848 EnterCriticalSection(&cleanup_helpers_cs); 849 if (p == cleanup_helpers_head) 850 cleanup_helpers_head = p->next; 851 else 852 p->prev->next = p->next; 853 if (p->next != NULL) 854 p->next->prev = p->prev; 855 LeaveCriticalSection(&cleanup_helpers_cs); 856 free(p); 857 } 858 } 859 break; 860 } 861 return TRUE; 862} 863#endif 864#define bottom_threads 865#include "elfgcchack.h" 866