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