Annotation of embedaddon/libxml2/threads.c, revision 1.1
1.1 ! misho 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:
! 49: static int libxml_is_threaded = -1;
! 50: #ifdef __GNUC__
! 51: #ifdef linux
! 52: #if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ > 3)
! 53: extern int pthread_once (pthread_once_t *__once_control,
! 54: void (*__init_routine) (void))
! 55: __attribute((weak));
! 56: extern void *pthread_getspecific (pthread_key_t __key)
! 57: __attribute((weak));
! 58: extern int pthread_setspecific (pthread_key_t __key,
! 59: __const void *__pointer)
! 60: __attribute((weak));
! 61: extern int pthread_key_create (pthread_key_t *__key,
! 62: void (*__destr_function) (void *))
! 63: __attribute((weak));
! 64: extern int pthread_key_delete (pthread_key_t __key)
! 65: __attribute((weak));
! 66: extern int pthread_mutex_init ()
! 67: __attribute((weak));
! 68: extern int pthread_mutex_destroy ()
! 69: __attribute((weak));
! 70: extern int pthread_mutex_lock ()
! 71: __attribute((weak));
! 72: extern int pthread_mutex_unlock ()
! 73: __attribute((weak));
! 74: extern int pthread_cond_init ()
! 75: __attribute((weak));
! 76: extern int pthread_cond_destroy ()
! 77: __attribute((weak));
! 78: extern int pthread_cond_wait ()
! 79: __attribute((weak));
! 80: extern int pthread_equal ()
! 81: __attribute((weak));
! 82: extern pthread_t pthread_self ()
! 83: __attribute((weak));
! 84: extern int pthread_key_create ()
! 85: __attribute((weak));
! 86: extern int pthread_key_delete ()
! 87: __attribute((weak));
! 88: extern 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: */
! 104: struct _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: */
! 120: struct _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
! 146: static pthread_key_t globalkey;
! 147: static pthread_t mainthread;
! 148: static pthread_once_t once_control = PTHREAD_ONCE_INIT;
! 149: static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
! 150: #elif defined HAVE_WIN32_THREADS
! 151: #if defined(HAVE_COMPILER_TLS)
! 152: static __declspec(thread) xmlGlobalState tlstate;
! 153: static __declspec(thread) int tlstate_inited = 0;
! 154: #else /* HAVE_COMPILER_TLS */
! 155: static DWORD globalkey = TLS_OUT_OF_INDEXES;
! 156: #endif /* HAVE_COMPILER_TLS */
! 157: static DWORD mainthread;
! 158: static struct {
! 159: DWORD done;
! 160: DWORD control;
! 161: } run_once = { 0, 0};
! 162: static volatile LPCRITICAL_SECTION global_init_lock = NULL;
! 163:
! 164: /* endif HAVE_WIN32_THREADS */
! 165: #elif defined HAVE_BEOS_THREADS
! 166: int32 globalkey = 0;
! 167: thread_id mainthread = 0;
! 168: int32 run_once_init = 0;
! 169: static int32 global_init_lock = -1;
! 170: static vint32 global_init_count = 0;
! 171: #endif
! 172:
! 173: static xmlRMutexPtr xmlLibraryLock = NULL;
! 174:
! 175: #ifdef LIBXML_THREAD_ENABLED
! 176: static void xmlOnceInit(void);
! 177: #endif
! 178:
! 179: /**
! 180: * xmlNewMutex:
! 181: *
! 182: * xmlNewMutex() is used to allocate a libxml2 token struct for use in
! 183: * synchronizing access to data.
! 184: *
! 185: * Returns a new simple mutex pointer or NULL in case of error
! 186: */
! 187: xmlMutexPtr
! 188: xmlNewMutex(void)
! 189: {
! 190: xmlMutexPtr tok;
! 191:
! 192: if ((tok = malloc(sizeof(xmlMutex))) == NULL)
! 193: return (NULL);
! 194: #ifdef HAVE_PTHREAD_H
! 195: if (libxml_is_threaded != 0)
! 196: pthread_mutex_init(&tok->lock, NULL);
! 197: #elif defined HAVE_WIN32_THREADS
! 198: tok->mutex = CreateMutex(NULL, FALSE, NULL);
! 199: #elif defined HAVE_BEOS_THREADS
! 200: if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) {
! 201: free(tok);
! 202: return NULL;
! 203: }
! 204: tok->tid = -1;
! 205: #endif
! 206: return (tok);
! 207: }
! 208:
! 209: /**
! 210: * xmlFreeMutex:
! 211: * @tok: the simple mutex
! 212: *
! 213: * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
! 214: * struct.
! 215: */
! 216: void
! 217: xmlFreeMutex(xmlMutexPtr tok)
! 218: {
! 219: if (tok == NULL)
! 220: return;
! 221:
! 222: #ifdef HAVE_PTHREAD_H
! 223: if (libxml_is_threaded != 0)
! 224: pthread_mutex_destroy(&tok->lock);
! 225: #elif defined HAVE_WIN32_THREADS
! 226: CloseHandle(tok->mutex);
! 227: #elif defined HAVE_BEOS_THREADS
! 228: delete_sem(tok->sem);
! 229: #endif
! 230: free(tok);
! 231: }
! 232:
! 233: /**
! 234: * xmlMutexLock:
! 235: * @tok: the simple mutex
! 236: *
! 237: * xmlMutexLock() is used to lock a libxml2 token.
! 238: */
! 239: void
! 240: xmlMutexLock(xmlMutexPtr tok)
! 241: {
! 242: if (tok == NULL)
! 243: return;
! 244: #ifdef HAVE_PTHREAD_H
! 245: if (libxml_is_threaded != 0)
! 246: pthread_mutex_lock(&tok->lock);
! 247: #elif defined HAVE_WIN32_THREADS
! 248: WaitForSingleObject(tok->mutex, INFINITE);
! 249: #elif defined HAVE_BEOS_THREADS
! 250: if (acquire_sem(tok->sem) != B_NO_ERROR) {
! 251: #ifdef DEBUG_THREADS
! 252: xmlGenericError(xmlGenericErrorContext,
! 253: "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
! 254: exit();
! 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: */
! 268: void
! 269: xmlMutexUnlock(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: */
! 296: xmlRMutexPtr
! 297: xmlNewRMutex(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: */
! 330: void
! 331: xmlFreeRMutex(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: */
! 354: void
! 355: xmlRMutexLock(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: */
! 399: void
! 400: xmlRMutexUnlock(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: */
! 436: void
! 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)
! 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: exit();
! 503: #endif
! 504: }
! 505: #endif
! 506: }
! 507:
! 508: void
! 509: __xmlGlobalInitMutexUnlock(void)
! 510: {
! 511: #ifdef HAVE_PTHREAD_H
! 512: if (pthread_mutex_unlock)
! 513: pthread_mutex_unlock(&global_init_lock);
! 514: #elif defined HAVE_WIN32_THREADS
! 515: if (global_init_lock != NULL) {
! 516: LeaveCriticalSection(global_init_lock);
! 517: }
! 518: #elif defined HAVE_BEOS_THREADS
! 519: release_sem(global_init_lock);
! 520: #endif
! 521: }
! 522:
! 523: /**
! 524: * xmlGlobalInitMutexDestroy
! 525: *
! 526: * Makes sure that the global initialization mutex is destroyed before
! 527: * application termination.
! 528: */
! 529: void
! 530: __xmlGlobalInitMutexDestroy(void)
! 531: {
! 532: #ifdef HAVE_PTHREAD_H
! 533: #elif defined HAVE_WIN32_THREADS
! 534: if (global_init_lock != NULL) {
! 535: DeleteCriticalSection(global_init_lock);
! 536: free(global_init_lock);
! 537: global_init_lock = NULL;
! 538: }
! 539: #endif
! 540: }
! 541:
! 542: /************************************************************************
! 543: * *
! 544: * Per thread global state handling *
! 545: * *
! 546: ************************************************************************/
! 547:
! 548: #ifdef LIBXML_THREAD_ENABLED
! 549: #ifdef xmlLastError
! 550: #undef xmlLastError
! 551: #endif
! 552:
! 553: /**
! 554: * xmlFreeGlobalState:
! 555: * @state: a thread global state
! 556: *
! 557: * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
! 558: * global state. It is is used here to reclaim memory resources.
! 559: */
! 560: static void
! 561: xmlFreeGlobalState(void *state)
! 562: {
! 563: xmlGlobalState *gs = (xmlGlobalState *) state;
! 564:
! 565: /* free any memory allocated in the thread's xmlLastError */
! 566: xmlResetError(&(gs->xmlLastError));
! 567: free(state);
! 568: }
! 569:
! 570: /**
! 571: * xmlNewGlobalState:
! 572: *
! 573: * xmlNewGlobalState() allocates a global state. This structure is used to
! 574: * hold all data for use by a thread when supporting backwards compatibility
! 575: * of libxml2 to pre-thread-safe behaviour.
! 576: *
! 577: * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
! 578: */
! 579: static xmlGlobalStatePtr
! 580: xmlNewGlobalState(void)
! 581: {
! 582: xmlGlobalState *gs;
! 583:
! 584: gs = malloc(sizeof(xmlGlobalState));
! 585: if (gs == NULL) {
! 586: xmlGenericError(xmlGenericErrorContext,
! 587: "xmlGetGlobalState: out of memory\n");
! 588: return (NULL);
! 589: }
! 590:
! 591: memset(gs, 0, sizeof(xmlGlobalState));
! 592: xmlInitializeGlobalState(gs);
! 593: return (gs);
! 594: }
! 595: #endif /* LIBXML_THREAD_ENABLED */
! 596:
! 597: #ifdef HAVE_PTHREAD_H
! 598: #elif defined HAVE_WIN32_THREADS
! 599: #if !defined(HAVE_COMPILER_TLS)
! 600: #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
! 601: typedef struct _xmlGlobalStateCleanupHelperParams {
! 602: HANDLE thread;
! 603: void *memory;
! 604: } xmlGlobalStateCleanupHelperParams;
! 605:
! 606: static void XMLCDECL
! 607: xmlGlobalStateCleanupHelper(void *p)
! 608: {
! 609: xmlGlobalStateCleanupHelperParams *params =
! 610: (xmlGlobalStateCleanupHelperParams *) p;
! 611: WaitForSingleObject(params->thread, INFINITE);
! 612: CloseHandle(params->thread);
! 613: xmlFreeGlobalState(params->memory);
! 614: free(params);
! 615: _endthread();
! 616: }
! 617: #else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
! 618:
! 619: typedef struct _xmlGlobalStateCleanupHelperParams {
! 620: void *memory;
! 621: struct _xmlGlobalStateCleanupHelperParams *prev;
! 622: struct _xmlGlobalStateCleanupHelperParams *next;
! 623: } xmlGlobalStateCleanupHelperParams;
! 624:
! 625: static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL;
! 626: static CRITICAL_SECTION cleanup_helpers_cs;
! 627:
! 628: #endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
! 629: #endif /* HAVE_COMPILER_TLS */
! 630: #endif /* HAVE_WIN32_THREADS */
! 631:
! 632: #if defined HAVE_BEOS_THREADS
! 633:
! 634: /**
! 635: * xmlGlobalStateCleanup:
! 636: * @data: unused parameter
! 637: *
! 638: * Used for Beos only
! 639: */
! 640: void
! 641: xmlGlobalStateCleanup(void *data)
! 642: {
! 643: void *globalval = tls_get(globalkey);
! 644:
! 645: if (globalval != NULL)
! 646: xmlFreeGlobalState(globalval);
! 647: }
! 648: #endif
! 649:
! 650: /**
! 651: * xmlGetGlobalState:
! 652: *
! 653: * xmlGetGlobalState() is called to retrieve the global state for a thread.
! 654: *
! 655: * Returns the thread global state or NULL in case of error
! 656: */
! 657: xmlGlobalStatePtr
! 658: xmlGetGlobalState(void)
! 659: {
! 660: #ifdef HAVE_PTHREAD_H
! 661: xmlGlobalState *globalval;
! 662:
! 663: if (libxml_is_threaded == 0)
! 664: return (NULL);
! 665:
! 666: pthread_once(&once_control, xmlOnceInit);
! 667:
! 668: if ((globalval = (xmlGlobalState *)
! 669: pthread_getspecific(globalkey)) == NULL) {
! 670: xmlGlobalState *tsd = xmlNewGlobalState();
! 671: if (tsd == NULL)
! 672: return(NULL);
! 673:
! 674: pthread_setspecific(globalkey, tsd);
! 675: return (tsd);
! 676: }
! 677: return (globalval);
! 678: #elif defined HAVE_WIN32_THREADS
! 679: #if defined(HAVE_COMPILER_TLS)
! 680: if (!tlstate_inited) {
! 681: tlstate_inited = 1;
! 682: xmlInitializeGlobalState(&tlstate);
! 683: }
! 684: return &tlstate;
! 685: #else /* HAVE_COMPILER_TLS */
! 686: xmlGlobalState *globalval;
! 687: xmlGlobalStateCleanupHelperParams *p;
! 688:
! 689: xmlOnceInit();
! 690: #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
! 691: globalval = (xmlGlobalState *) TlsGetValue(globalkey);
! 692: #else
! 693: p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey);
! 694: globalval = (xmlGlobalState *) (p ? p->memory : NULL);
! 695: #endif
! 696: if (globalval == NULL) {
! 697: xmlGlobalState *tsd = xmlNewGlobalState();
! 698:
! 699: if (tsd == NULL)
! 700: return(NULL);
! 701: p = (xmlGlobalStateCleanupHelperParams *)
! 702: malloc(sizeof(xmlGlobalStateCleanupHelperParams));
! 703: if (p == NULL) {
! 704: xmlGenericError(xmlGenericErrorContext,
! 705: "xmlGetGlobalState: out of memory\n");
! 706: xmlFreeGlobalState(tsd);
! 707: return(NULL);
! 708: }
! 709: p->memory = tsd;
! 710: #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
! 711: DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
! 712: GetCurrentProcess(), &p->thread, 0, TRUE,
! 713: DUPLICATE_SAME_ACCESS);
! 714: TlsSetValue(globalkey, tsd);
! 715: _beginthread(xmlGlobalStateCleanupHelper, 0, p);
! 716: #else
! 717: EnterCriticalSection(&cleanup_helpers_cs);
! 718: if (cleanup_helpers_head != NULL) {
! 719: cleanup_helpers_head->prev = p;
! 720: }
! 721: p->next = cleanup_helpers_head;
! 722: p->prev = NULL;
! 723: cleanup_helpers_head = p;
! 724: TlsSetValue(globalkey, p);
! 725: LeaveCriticalSection(&cleanup_helpers_cs);
! 726: #endif
! 727:
! 728: return (tsd);
! 729: }
! 730: return (globalval);
! 731: #endif /* HAVE_COMPILER_TLS */
! 732: #elif defined HAVE_BEOS_THREADS
! 733: xmlGlobalState *globalval;
! 734:
! 735: xmlOnceInit();
! 736:
! 737: if ((globalval = (xmlGlobalState *) tls_get(globalkey)) == NULL) {
! 738: xmlGlobalState *tsd = xmlNewGlobalState();
! 739: if (tsd == NULL)
! 740: return (NULL);
! 741:
! 742: tls_set(globalkey, tsd);
! 743: on_exit_thread(xmlGlobalStateCleanup, NULL);
! 744: return (tsd);
! 745: }
! 746: return (globalval);
! 747: #else
! 748: return (NULL);
! 749: #endif
! 750: }
! 751:
! 752: /************************************************************************
! 753: * *
! 754: * Library wide thread interfaces *
! 755: * *
! 756: ************************************************************************/
! 757:
! 758: /**
! 759: * xmlGetThreadId:
! 760: *
! 761: * xmlGetThreadId() find the current thread ID number
! 762: * Note that this is likely to be broken on some platforms using pthreads
! 763: * as the specification doesn't mandate pthread_t to be an integer type
! 764: *
! 765: * Returns the current thread ID number
! 766: */
! 767: int
! 768: xmlGetThreadId(void)
! 769: {
! 770: #ifdef HAVE_PTHREAD_H
! 771: pthread_t id;
! 772: int ret;
! 773:
! 774: if (libxml_is_threaded == 0)
! 775: return (0);
! 776: id = pthread_self();
! 777: /* horrible but preserves compat, see warning above */
! 778: memcpy(&ret, &id, sizeof(ret));
! 779: return (ret);
! 780: #elif defined HAVE_WIN32_THREADS
! 781: return GetCurrentThreadId();
! 782: #elif defined HAVE_BEOS_THREADS
! 783: return find_thread(NULL);
! 784: #else
! 785: return ((int) 0);
! 786: #endif
! 787: }
! 788:
! 789: /**
! 790: * xmlIsMainThread:
! 791: *
! 792: * xmlIsMainThread() check whether the current thread is the main thread.
! 793: *
! 794: * Returns 1 if the current thread is the main thread, 0 otherwise
! 795: */
! 796: int
! 797: xmlIsMainThread(void)
! 798: {
! 799: #ifdef HAVE_PTHREAD_H
! 800: if (libxml_is_threaded == -1)
! 801: xmlInitThreads();
! 802: if (libxml_is_threaded == 0)
! 803: return (1);
! 804: pthread_once(&once_control, xmlOnceInit);
! 805: #elif defined HAVE_WIN32_THREADS
! 806: xmlOnceInit();
! 807: #elif defined HAVE_BEOS_THREADS
! 808: xmlOnceInit();
! 809: #endif
! 810:
! 811: #ifdef DEBUG_THREADS
! 812: xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
! 813: #endif
! 814: #ifdef HAVE_PTHREAD_H
! 815: return (pthread_equal(mainthread,pthread_self()));
! 816: #elif defined HAVE_WIN32_THREADS
! 817: return (mainthread == GetCurrentThreadId());
! 818: #elif defined HAVE_BEOS_THREADS
! 819: return (mainthread == find_thread(NULL));
! 820: #else
! 821: return (1);
! 822: #endif
! 823: }
! 824:
! 825: /**
! 826: * xmlLockLibrary:
! 827: *
! 828: * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
! 829: * library.
! 830: */
! 831: void
! 832: xmlLockLibrary(void)
! 833: {
! 834: #ifdef DEBUG_THREADS
! 835: xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
! 836: #endif
! 837: xmlRMutexLock(xmlLibraryLock);
! 838: }
! 839:
! 840: /**
! 841: * xmlUnlockLibrary:
! 842: *
! 843: * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
! 844: * library.
! 845: */
! 846: void
! 847: xmlUnlockLibrary(void)
! 848: {
! 849: #ifdef DEBUG_THREADS
! 850: xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
! 851: #endif
! 852: xmlRMutexUnlock(xmlLibraryLock);
! 853: }
! 854:
! 855: /**
! 856: * xmlInitThreads:
! 857: *
! 858: * xmlInitThreads() is used to to initialize all the thread related
! 859: * data of the libxml2 library.
! 860: */
! 861: void
! 862: xmlInitThreads(void)
! 863: {
! 864: #ifdef HAVE_PTHREAD_H
! 865: if (libxml_is_threaded == -1) {
! 866: if ((pthread_once != NULL) &&
! 867: (pthread_getspecific != NULL) &&
! 868: (pthread_setspecific != NULL) &&
! 869: (pthread_key_create != NULL) &&
! 870: (pthread_key_delete != NULL) &&
! 871: (pthread_mutex_init != NULL) &&
! 872: (pthread_mutex_destroy != NULL) &&
! 873: (pthread_mutex_lock != NULL) &&
! 874: (pthread_mutex_unlock != NULL) &&
! 875: (pthread_cond_init != NULL) &&
! 876: (pthread_cond_destroy != NULL) &&
! 877: (pthread_cond_wait != NULL) &&
! 878: (pthread_equal != NULL) &&
! 879: (pthread_self != NULL) &&
! 880: (pthread_cond_signal != NULL)) {
! 881: libxml_is_threaded = 1;
! 882:
! 883: /* fprintf(stderr, "Running multithreaded\n"); */
! 884: } else {
! 885:
! 886: /* fprintf(stderr, "Running without multithread\n"); */
! 887: libxml_is_threaded = 0;
! 888: }
! 889: }
! 890: #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
! 891: InitializeCriticalSection(&cleanup_helpers_cs);
! 892: #endif
! 893: }
! 894:
! 895: /**
! 896: * xmlCleanupThreads:
! 897: *
! 898: * xmlCleanupThreads() is used to to cleanup all the thread related
! 899: * data of the libxml2 library once processing has ended.
! 900: *
! 901: * WARNING: if your application is multithreaded or has plugin support
! 902: * calling this may crash the application if another thread or
! 903: * a plugin is still using libxml2. It's sometimes very hard to
! 904: * guess if libxml2 is in use in the application, some libraries
! 905: * or plugins may use it without notice. In case of doubt abstain
! 906: * from calling this function or do it just before calling exit()
! 907: * to avoid leak reports from valgrind !
! 908: */
! 909: void
! 910: xmlCleanupThreads(void)
! 911: {
! 912: #ifdef DEBUG_THREADS
! 913: xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
! 914: #endif
! 915: #ifdef HAVE_PTHREAD_H
! 916: if ((libxml_is_threaded) && (pthread_key_delete != NULL))
! 917: pthread_key_delete(globalkey);
! 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: */
! 951: static void
! 952: xmlOnceInit(void)
! 953: {
! 954: #ifdef HAVE_PTHREAD_H
! 955: (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
! 956: mainthread = pthread_self();
! 957: #elif defined(HAVE_WIN32_THREADS)
! 958: if (!run_once.done) {
! 959: if (InterlockedIncrement(&run_once.control) == 1) {
! 960: #if !defined(HAVE_COMPILER_TLS)
! 961: globalkey = TlsAlloc();
! 962: #endif
! 963: mainthread = GetCurrentThreadId();
! 964: run_once.done = 1;
! 965: } else {
! 966: /* Another thread is working; give up our slice and
! 967: * wait until they're done. */
! 968: while (!run_once.done)
! 969: Sleep(0);
! 970: }
! 971: }
! 972: #elif defined HAVE_BEOS_THREADS
! 973: if (atomic_add(&run_once_init, 1) == 0) {
! 974: globalkey = tls_allocate();
! 975: tls_set(globalkey, NULL);
! 976: mainthread = find_thread(NULL);
! 977: } else
! 978: atomic_add(&run_once_init, -1);
! 979: #endif
! 980: }
! 981: #endif
! 982:
! 983: /**
! 984: * DllMain:
! 985: * @hinstDLL: handle to DLL instance
! 986: * @fdwReason: Reason code for entry
! 987: * @lpvReserved: generic pointer (depends upon reason code)
! 988: *
! 989: * Entry point for Windows library. It is being used to free thread-specific
! 990: * storage.
! 991: *
! 992: * Returns TRUE always
! 993: */
! 994: #ifdef HAVE_PTHREAD_H
! 995: #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
! 996: #if defined(LIBXML_STATIC_FOR_DLL)
! 997: BOOL XMLCALL
! 998: xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
! 999: #else
! 1000: BOOL WINAPI
! 1001: DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
! 1002: #endif
! 1003: {
! 1004: switch (fdwReason) {
! 1005: case DLL_THREAD_DETACH:
! 1006: if (globalkey != TLS_OUT_OF_INDEXES) {
! 1007: xmlGlobalState *globalval = NULL;
! 1008: xmlGlobalStateCleanupHelperParams *p =
! 1009: (xmlGlobalStateCleanupHelperParams *)
! 1010: TlsGetValue(globalkey);
! 1011: globalval = (xmlGlobalState *) (p ? p->memory : NULL);
! 1012: if (globalval) {
! 1013: xmlFreeGlobalState(globalval);
! 1014: TlsSetValue(globalkey, NULL);
! 1015: }
! 1016: if (p) {
! 1017: EnterCriticalSection(&cleanup_helpers_cs);
! 1018: if (p == cleanup_helpers_head)
! 1019: cleanup_helpers_head = p->next;
! 1020: else
! 1021: p->prev->next = p->next;
! 1022: if (p->next != NULL)
! 1023: p->next->prev = p->prev;
! 1024: LeaveCriticalSection(&cleanup_helpers_cs);
! 1025: free(p);
! 1026: }
! 1027: }
! 1028: break;
! 1029: }
! 1030: return TRUE;
! 1031: }
! 1032: #endif
! 1033: #define bottom_threads
! 1034: #include "elfgcchack.h"
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>