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 pthread_cond_destroy(&tok->cv); 325 } 326#elif defined HAVE_WIN32_THREADS 327 DeleteCriticalSection(&tok->cs); 328#elif defined HAVE_BEOS_THREADS 329 xmlFreeMutex(tok->lock); 330#endif 331 free(tok); 332} 333 334/** 335 * xmlRMutexLock: 336 * @tok: the reentrant mutex 337 * 338 * xmlRMutexLock() is used to lock a libxml2 token_r. 339 */ 340void 341xmlRMutexLock(xmlRMutexPtr tok) 342{ 343 if (tok == NULL) 344 return; 345#ifdef HAVE_PTHREAD_H 346 if (libxml_is_threaded == 0) 347 return; 348 349 pthread_mutex_lock(&tok->lock); 350 if (tok->held) { 351 if (pthread_equal(tok->tid, pthread_self())) { 352 tok->held++; 353 pthread_mutex_unlock(&tok->lock); 354 return; 355 } else { 356 tok->waiters++; 357 while (tok->held) 358 pthread_cond_wait(&tok->cv, &tok->lock); 359 tok->waiters--; 360 } 361 } 362 tok->tid = pthread_self(); 363 tok->held = 1; 364 pthread_mutex_unlock(&tok->lock); 365#elif defined HAVE_WIN32_THREADS 366 EnterCriticalSection(&tok->cs); 367 ++tok->count; 368#elif defined HAVE_BEOS_THREADS 369 if (tok->lock->tid == find_thread(NULL)) { 370 tok->count++; 371 return; 372 } else { 373 xmlMutexLock(tok->lock); 374 tok->count = 1; 375 } 376#endif 377} 378 379/** 380 * xmlRMutexUnlock: 381 * @tok: the reentrant mutex 382 * 383 * xmlRMutexUnlock() is used to unlock a libxml2 token_r. 384 */ 385void 386xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED) 387{ 388 if (tok == NULL) 389 return; 390#ifdef HAVE_PTHREAD_H 391 if (libxml_is_threaded == 0) 392 return; 393 394 pthread_mutex_lock(&tok->lock); 395 tok->held--; 396 if (tok->held == 0) { 397 if (tok->waiters) 398 pthread_cond_signal(&tok->cv); 399 tok->tid = 0; 400 } 401 pthread_mutex_unlock(&tok->lock); 402#elif defined HAVE_WIN32_THREADS 403 if (!--tok->count) 404 LeaveCriticalSection(&tok->cs); 405#elif defined HAVE_BEOS_THREADS 406 if (tok->lock->tid == find_thread(NULL)) { 407 tok->count--; 408 if (tok->count == 0) { 409 xmlMutexUnlock(tok->lock); 410 } 411 return; 412 } 413#endif 414} 415 416/************************************************************************ 417 * * 418 * Per thread global state handling * 419 * * 420 ************************************************************************/ 421 422#ifdef LIBXML_THREAD_ENABLED 423#ifdef xmlLastError 424#undef xmlLastError 425#endif 426/** 427 * xmlFreeGlobalState: 428 * @state: a thread global state 429 * 430 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL 431 * global state. It is is used here to reclaim memory resources. 432 */ 433static void 434xmlFreeGlobalState(void *state) 435{ 436 xmlGlobalState *gs = (xmlGlobalState *) state; 437 438 /* free any memory allocated in the thread's xmlLastError */ 439 xmlResetError(&(gs->xmlLastError)); 440 free(state); 441} 442 443/** 444 * xmlNewGlobalState: 445 * 446 * xmlNewGlobalState() allocates a global state. This structure is used to 447 * hold all data for use by a thread when supporting backwards compatibility 448 * of libxml2 to pre-thread-safe behaviour. 449 * 450 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error 451 */ 452static xmlGlobalStatePtr 453xmlNewGlobalState(void) 454{ 455 xmlGlobalState *gs; 456 457 gs = malloc(sizeof(xmlGlobalState)); 458 if (gs == NULL) 459 return(NULL); 460 461 memset(gs, 0, sizeof(xmlGlobalState)); 462 xmlInitializeGlobalState(gs); 463 return (gs); 464} 465#endif /* LIBXML_THREAD_ENABLED */ 466 467 468#ifdef HAVE_WIN32_THREADS 469#if !defined(HAVE_COMPILER_TLS) 470#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) 471typedef struct _xmlGlobalStateCleanupHelperParams 472{ 473 HANDLE thread; 474 void *memory; 475} xmlGlobalStateCleanupHelperParams; 476 477static void XMLCDECL xmlGlobalStateCleanupHelper (void *p) 478{ 479 xmlGlobalStateCleanupHelperParams *params = (xmlGlobalStateCleanupHelperParams *) p; 480 WaitForSingleObject(params->thread, INFINITE); 481 CloseHandle(params->thread); 482 xmlFreeGlobalState(params->memory); 483 free(params); 484 _endthread(); 485} 486#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */ 487 488typedef struct _xmlGlobalStateCleanupHelperParams 489{ 490 void *memory; 491 struct _xmlGlobalStateCleanupHelperParams * prev; 492 struct _xmlGlobalStateCleanupHelperParams * next; 493} xmlGlobalStateCleanupHelperParams; 494 495static xmlGlobalStateCleanupHelperParams * cleanup_helpers_head = NULL; 496static CRITICAL_SECTION cleanup_helpers_cs; 497 498#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */ 499#endif /* HAVE_COMPILER_TLS */ 500#endif /* HAVE_WIN32_THREADS */ 501 502#if defined HAVE_BEOS_THREADS 503/** 504 * xmlGlobalStateCleanup: 505 * @data: unused parameter 506 * 507 * Used for Beos only 508 */ 509void xmlGlobalStateCleanup(void *data) 510{ 511 void *globalval = tls_get(globalkey); 512 if (globalval != NULL) 513 xmlFreeGlobalState(globalval); 514} 515#endif 516 517/** 518 * xmlGetGlobalState: 519 * 520 * xmlGetGlobalState() is called to retrieve the global state for a thread. 521 * 522 * Returns the thread global state or NULL in case of error 523 */ 524xmlGlobalStatePtr 525xmlGetGlobalState(void) 526{ 527#ifdef HAVE_PTHREAD_H 528 xmlGlobalState *globalval; 529 530 if (libxml_is_threaded == 0) 531 return(NULL); 532 533 pthread_once(&once_control, xmlOnceInit); 534 535 if ((globalval = (xmlGlobalState *) 536 pthread_getspecific(globalkey)) == NULL) { 537 xmlGlobalState *tsd = xmlNewGlobalState(); 538 539 pthread_setspecific(globalkey, tsd); 540 return (tsd); 541 } 542 return (globalval); 543#elif defined HAVE_WIN32_THREADS 544#if defined(HAVE_COMPILER_TLS) 545 if (!tlstate_inited) { 546 tlstate_inited = 1; 547 xmlInitializeGlobalState(&tlstate); 548 } 549 return &tlstate; 550#else /* HAVE_COMPILER_TLS */ 551 xmlGlobalState *globalval; 552 xmlGlobalStateCleanupHelperParams * p; 553 554 xmlOnceInit(); 555#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) 556 globalval = (xmlGlobalState *)TlsGetValue(globalkey); 557#else 558 p = (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey); 559 globalval = (xmlGlobalState *)(p ? p->memory : NULL); 560#endif 561 if (globalval == NULL) { 562 xmlGlobalState *tsd = xmlNewGlobalState(); 563 p = (xmlGlobalStateCleanupHelperParams *) malloc(sizeof(xmlGlobalStateCleanupHelperParams)); 564 p->memory = tsd; 565#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) 566 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), 567 GetCurrentProcess(), &p->thread, 0, TRUE, DUPLICATE_SAME_ACCESS); 568 TlsSetValue(globalkey, tsd); 569 _beginthread(xmlGlobalStateCleanupHelper, 0, p); 570#else 571 EnterCriticalSection(&cleanup_helpers_cs); 572 if (cleanup_helpers_head != NULL) { 573 cleanup_helpers_head->prev = p; 574 } 575 p->next = cleanup_helpers_head; 576 p->prev = NULL; 577 cleanup_helpers_head = p; 578 TlsSetValue(globalkey, p); 579 LeaveCriticalSection(&cleanup_helpers_cs); 580#endif 581 582 return (tsd); 583 } 584 return (globalval); 585#endif /* HAVE_COMPILER_TLS */ 586#elif defined HAVE_BEOS_THREADS 587 xmlGlobalState *globalval; 588 589 xmlOnceInit(); 590 591 if ((globalval = (xmlGlobalState *) 592 tls_get(globalkey)) == NULL) { 593 xmlGlobalState *tsd = xmlNewGlobalState(); 594 595 tls_set(globalkey, tsd); 596 on_exit_thread(xmlGlobalStateCleanup, NULL); 597 return (tsd); 598 } 599 return (globalval); 600#else 601 return(NULL); 602#endif 603} 604 605/************************************************************************ 606 * * 607 * Library wide thread interfaces * 608 * * 609 ************************************************************************/ 610 611/** 612 * xmlGetThreadId: 613 * 614 * xmlGetThreadId() find the current thread ID number 615 * 616 * Returns the current thread ID number 617 */ 618int 619xmlGetThreadId(void) 620{ 621#ifdef HAVE_PTHREAD_H 622 if (libxml_is_threaded == 0) 623 return(0); 624 return((int) pthread_self()); 625#elif defined HAVE_WIN32_THREADS 626 return GetCurrentThreadId(); 627#elif defined HAVE_BEOS_THREADS 628 return find_thread(NULL); 629#else 630 return((int) 0); 631#endif 632} 633 634/** 635 * xmlIsMainThread: 636 * 637 * xmlIsMainThread() check whether the current thread is the main thread. 638 * 639 * Returns 1 if the current thread is the main thread, 0 otherwise 640 */ 641int 642xmlIsMainThread(void) 643{ 644#ifdef HAVE_PTHREAD_H 645 if (libxml_is_threaded == -1) 646 xmlInitThreads(); 647 if (libxml_is_threaded == 0) 648 return(1); 649 pthread_once(&once_control, xmlOnceInit); 650#elif defined HAVE_WIN32_THREADS 651 xmlOnceInit (); 652#elif defined HAVE_BEOS_THREADS 653 xmlOnceInit(); 654#endif 655 656#ifdef DEBUG_THREADS 657 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n"); 658#endif 659#ifdef HAVE_PTHREAD_H 660 return(mainthread == pthread_self()); 661#elif defined HAVE_WIN32_THREADS 662 return(mainthread == GetCurrentThreadId ()); 663#elif defined HAVE_BEOS_THREADS 664 return(mainthread == find_thread(NULL)); 665#else 666 return(1); 667#endif 668} 669 670/** 671 * xmlLockLibrary: 672 * 673 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2 674 * library. 675 */ 676void 677xmlLockLibrary(void) 678{ 679#ifdef DEBUG_THREADS 680 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n"); 681#endif 682 xmlRMutexLock(xmlLibraryLock); 683} 684 685/** 686 * xmlUnlockLibrary: 687 * 688 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2 689 * library. 690 */ 691void 692xmlUnlockLibrary(void) 693{ 694#ifdef DEBUG_THREADS 695 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n"); 696#endif 697 xmlRMutexUnlock(xmlLibraryLock); 698} 699 700/** 701 * xmlInitThreads: 702 * 703 * xmlInitThreads() is used to to initialize all the thread related 704 * data of the libxml2 library. 705 */ 706void 707xmlInitThreads(void) 708{ 709#ifdef DEBUG_THREADS 710 xmlGenericError(xmlGenericErrorContext, "xmlInitThreads()\n"); 711#endif 712#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) 713 InitializeCriticalSection(&cleanup_helpers_cs); 714#endif 715#ifdef HAVE_PTHREAD_H 716 if (libxml_is_threaded == -1) { 717 if ((pthread_once != NULL) && 718 (pthread_getspecific != NULL) && 719 (pthread_setspecific != NULL) && 720 (pthread_key_create != NULL) && 721 (pthread_mutex_init != NULL) && 722 (pthread_mutex_destroy != NULL) && 723 (pthread_mutex_lock != NULL) && 724 (pthread_mutex_unlock != NULL) && 725 (pthread_cond_init != NULL) && 726 (pthread_equal != NULL) && 727 (pthread_self != NULL) && 728 (pthread_key_create != NULL) && 729 (pthread_cond_signal != NULL)) { 730 libxml_is_threaded = 1; 731/* fprintf(stderr, "Running multithreaded\n"); */ 732 } else { 733/* fprintf(stderr, "Running without multithread\n"); */ 734 libxml_is_threaded = 0; 735 } 736 } 737#endif 738} 739 740/** 741 * xmlCleanupThreads: 742 * 743 * xmlCleanupThreads() is used to to cleanup all the thread related 744 * data of the libxml2 library once processing has ended. 745 */ 746void 747xmlCleanupThreads(void) 748{ 749#ifdef DEBUG_THREADS 750 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n"); 751#endif 752#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) 753 if (globalkey != TLS_OUT_OF_INDEXES) { 754 xmlGlobalStateCleanupHelperParams * p; 755 EnterCriticalSection(&cleanup_helpers_cs); 756 p = cleanup_helpers_head; 757 while (p != NULL) { 758 xmlGlobalStateCleanupHelperParams * temp = p; 759 p = p->next; 760 xmlFreeGlobalState(temp->memory); 761 free(temp); 762 } 763 cleanup_helpers_head = 0; 764 LeaveCriticalSection(&cleanup_helpers_cs); 765 TlsFree(globalkey); 766 globalkey = TLS_OUT_OF_INDEXES; 767 } 768 DeleteCriticalSection(&cleanup_helpers_cs); 769#endif 770} 771 772#ifdef LIBXML_THREAD_ENABLED 773/** 774 * xmlOnceInit 775 * 776 * xmlOnceInit() is used to initialize the value of mainthread for use 777 * in other routines. This function should only be called using 778 * pthread_once() in association with the once_control variable to ensure 779 * that the function is only called once. See man pthread_once for more 780 * details. 781 */ 782static void 783xmlOnceInit(void) { 784#ifdef HAVE_PTHREAD_H 785 (void) pthread_key_create(&globalkey, xmlFreeGlobalState); 786 mainthread = pthread_self(); 787#endif 788 789#if defined(HAVE_WIN32_THREADS) 790 if (!run_once.done) { 791 if (InterlockedIncrement(&run_once.control) == 1) 792 { 793#if !defined(HAVE_COMPILER_TLS) 794 globalkey = TlsAlloc(); 795#endif 796 mainthread = GetCurrentThreadId(); 797 run_once.done = 1; 798 } 799 else { 800 /* Another thread is working; give up our slice and 801 * wait until they're done. */ 802 while (!run_once.done) 803 Sleep(0); 804 } 805 } 806#endif 807 808#ifdef HAVE_BEOS_THREADS 809 if (atomic_add(&run_once_init, 1) == 0) { 810 globalkey = tls_allocate(); 811 tls_set(globalkey, NULL); 812 mainthread = find_thread(NULL); 813 } else 814 atomic_add(&run_once_init, -1); 815#endif 816} 817#endif 818 819/** 820 * DllMain: 821 * @hinstDLL: handle to DLL instance 822 * @fdwReason: Reason code for entry 823 * @lpvReserved: generic pointer (depends upon reason code) 824 * 825 * Entry point for Windows library. It is being used to free thread-specific 826 * storage. 827 * 828 * Returns TRUE always 829 */ 830#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) 831#if defined(LIBXML_STATIC_FOR_DLL) 832BOOL WINAPI xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 833#else 834BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 835#endif 836{ 837 switch(fdwReason) { 838 case DLL_THREAD_DETACH: 839 if (globalkey != TLS_OUT_OF_INDEXES) { 840 xmlGlobalState *globalval = NULL; 841 xmlGlobalStateCleanupHelperParams * p = 842 (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey); 843 globalval = (xmlGlobalState *)(p ? p->memory : NULL); 844 if (globalval) { 845 xmlFreeGlobalState(globalval); 846 TlsSetValue(globalkey,NULL); 847 } 848 if (p) 849 { 850 EnterCriticalSection(&cleanup_helpers_cs); 851 if (p == cleanup_helpers_head) 852 cleanup_helpers_head = p->next; 853 else 854 p->prev->next = p->next; 855 if (p->next != NULL) 856 p->next->prev = p->prev; 857 LeaveCriticalSection(&cleanup_helpers_cs); 858 free(p); 859 } 860 } 861 break; 862 } 863 return TRUE; 864} 865#endif 866#define bottom_threads 867#include "elfgcchack.h" 868