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 #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 #if defined(__GNUC__) && defined(__GLIBC__)
     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 /* defined(__GNUC__) && defined(__GLIBC__) */
     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_once_t once_control_init = PTHREAD_ONCE_INIT;
    150 static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
    151 #elif defined HAVE_WIN32_THREADS
    152 #if defined(HAVE_COMPILER_TLS)
    153 static __declspec(thread) xmlGlobalState tlstate;
    154 static __declspec(thread) int tlstate_inited = 0;
    155 #else /* HAVE_COMPILER_TLS */
    156 static DWORD globalkey = TLS_OUT_OF_INDEXES;
    157 #endif /* HAVE_COMPILER_TLS */
    158 static DWORD mainthread;
    159 static struct {
    160     DWORD done;
    161     DWORD control;
    162 } run_once = { 0, 0};
    163 static volatile LPCRITICAL_SECTION global_init_lock = NULL;
    164 
    165 /* endif HAVE_WIN32_THREADS */
    166 #elif defined HAVE_BEOS_THREADS
    167 int32 globalkey = 0;
    168 thread_id mainthread = 0;
    169 int32 run_once_init = 0;
    170 static int32 global_init_lock = -1;
    171 static vint32 global_init_count = 0;
    172 #endif
    173 
    174 static xmlRMutexPtr xmlLibraryLock = NULL;
    175 
    176 #ifdef LIBXML_THREAD_ENABLED
    177 static void xmlOnceInit(void);
    178 #endif
    179 
    180 /**
    181  * xmlNewMutex:
    182  *
    183  * xmlNewMutex() is used to allocate a libxml2 token struct for use in
    184  * synchronizing access to data.
    185  *
    186  * Returns a new simple mutex pointer or NULL in case of error
    187  */
    188 xmlMutexPtr
    189 xmlNewMutex(void)
    190 {
    191     xmlMutexPtr tok;
    192 
    193     if ((tok = malloc(sizeof(xmlMutex))) == NULL)
    194         return (NULL);
    195 #ifdef HAVE_PTHREAD_H
    196     if (libxml_is_threaded != 0)
    197         pthread_mutex_init(&tok->lock, NULL);
    198 #elif defined HAVE_WIN32_THREADS
    199     tok->mutex = CreateMutex(NULL, FALSE, NULL);
    200 #elif defined HAVE_BEOS_THREADS
    201     if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) {
    202         free(tok);
    203         return NULL;
    204     }
    205     tok->tid = -1;
    206 #endif
    207     return (tok);
    208 }
    209 
    210 /**
    211  * xmlFreeMutex:
    212  * @tok:  the simple mutex
    213  *
    214  * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
    215  * struct.
    216  */
    217 void
    218 xmlFreeMutex(xmlMutexPtr tok)
    219 {
    220     if (tok == NULL)
    221         return;
    222 
    223 #ifdef HAVE_PTHREAD_H
    224     if (libxml_is_threaded != 0)
    225         pthread_mutex_destroy(&tok->lock);
    226 #elif defined HAVE_WIN32_THREADS
    227     CloseHandle(tok->mutex);
    228 #elif defined HAVE_BEOS_THREADS
    229     delete_sem(tok->sem);
    230 #endif
    231     free(tok);
    232 }
    233 
    234 /**
    235  * xmlMutexLock:
    236  * @tok:  the simple mutex
    237  *
    238  * xmlMutexLock() is used to lock a libxml2 token.
    239  */
    240 void
    241 xmlMutexLock(xmlMutexPtr tok)
    242 {
    243     if (tok == NULL)
    244         return;
    245 #ifdef HAVE_PTHREAD_H
    246     if (libxml_is_threaded != 0)
    247         pthread_mutex_lock(&tok->lock);
    248 #elif defined HAVE_WIN32_THREADS
    249     WaitForSingleObject(tok->mutex, INFINITE);
    250 #elif defined HAVE_BEOS_THREADS
    251     if (acquire_sem(tok->sem) != B_NO_ERROR) {
    252 #ifdef DEBUG_THREADS
    253         xmlGenericError(xmlGenericErrorContext,
    254                         "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
    255 #endif
    256     }
    257     tok->tid = find_thread(NULL);
    258 #endif
    259 
    260 }
    261 
    262 /**
    263  * xmlMutexUnlock:
    264  * @tok:  the simple mutex
    265  *
    266  * xmlMutexUnlock() is used to unlock a libxml2 token.
    267  */
    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 > 0) {
    418 	tok->count--;
    419         LeaveCriticalSection(&tok->cs);
    420     }
    421 #elif defined HAVE_BEOS_THREADS
    422     if (tok->lock->tid == find_thread(NULL)) {
    423         tok->count--;
    424         if (tok->count == 0) {
    425             xmlMutexUnlock(tok->lock);
    426         }
    427         return;
    428     }
    429 #endif
    430 }
    431 
    432 /**
    433  * xmlGlobalInitMutexLock
    434  *
    435  * Makes sure that the global initialization mutex is initialized and
    436  * locks it.
    437  */
    438 void
    439 __xmlGlobalInitMutexLock(void)
    440 {
    441     /* Make sure the global init lock is initialized and then lock it. */
    442 #ifdef HAVE_PTHREAD_H
    443     /* The mutex is statically initialized, so we just lock it. */
    444     if (pthread_mutex_lock != NULL)
    445         pthread_mutex_lock(&global_init_lock);
    446 #elif defined HAVE_WIN32_THREADS
    447     LPCRITICAL_SECTION cs;
    448 
    449     /* Create a new critical section */
    450     if (global_init_lock == NULL) {
    451         cs = malloc(sizeof(CRITICAL_SECTION));
    452         if (cs == NULL) {
    453             xmlGenericError(xmlGenericErrorContext,
    454                             "xmlGlobalInitMutexLock: out of memory\n");
    455             return;
    456         }
    457         InitializeCriticalSection(cs);
    458 
    459         /* Swap it into the global_init_lock */
    460 #ifdef InterlockedCompareExchangePointer
    461         InterlockedCompareExchangePointer(&global_init_lock, cs, NULL);
    462 #else /* Use older void* version */
    463         InterlockedCompareExchange((void **) &global_init_lock,
    464                                    (void *) cs, NULL);
    465 #endif /* InterlockedCompareExchangePointer */
    466 
    467         /* If another thread successfully recorded its critical
    468          * section in the global_init_lock then discard the one
    469          * allocated by this thread. */
    470         if (global_init_lock != cs) {
    471             DeleteCriticalSection(cs);
    472             free(cs);
    473         }
    474     }
    475 
    476     /* Lock the chosen critical section */
    477     EnterCriticalSection(global_init_lock);
    478 #elif defined HAVE_BEOS_THREADS
    479     int32 sem;
    480 
    481     /* Allocate a new semaphore */
    482     sem = create_sem(1, "xmlGlobalinitMutex");
    483 
    484     while (global_init_lock == -1) {
    485         if (atomic_add(&global_init_count, 1) == 0) {
    486             global_init_lock = sem;
    487         } else {
    488             snooze(1);
    489             atomic_add(&global_init_count, -1);
    490         }
    491     }
    492 
    493     /* If another thread successfully recorded its critical
    494      * section in the global_init_lock then discard the one
    495      * allocated by this thread. */
    496     if (global_init_lock != sem)
    497         delete_sem(sem);
    498 
    499     /* Acquire the chosen semaphore */
    500     if (acquire_sem(global_init_lock) != B_NO_ERROR) {
    501 #ifdef DEBUG_THREADS
    502         xmlGenericError(xmlGenericErrorContext,
    503                         "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n");
    504 #endif
    505     }
    506 #endif
    507 }
    508 
    509 void
    510 __xmlGlobalInitMutexUnlock(void)
    511 {
    512 #ifdef HAVE_PTHREAD_H
    513     if (pthread_mutex_unlock != NULL)
    514         pthread_mutex_unlock(&global_init_lock);
    515 #elif defined HAVE_WIN32_THREADS
    516     if (global_init_lock != NULL) {
    517 	LeaveCriticalSection(global_init_lock);
    518     }
    519 #elif defined HAVE_BEOS_THREADS
    520     release_sem(global_init_lock);
    521 #endif
    522 }
    523 
    524 /**
    525  * xmlGlobalInitMutexDestroy
    526  *
    527  * Makes sure that the global initialization mutex is destroyed before
    528  * application termination.
    529  */
    530 void
    531 __xmlGlobalInitMutexDestroy(void)
    532 {
    533 #ifdef HAVE_PTHREAD_H
    534 #elif defined HAVE_WIN32_THREADS
    535     if (global_init_lock != NULL) {
    536         DeleteCriticalSection(global_init_lock);
    537         free(global_init_lock);
    538         global_init_lock = NULL;
    539     }
    540 #endif
    541 }
    542 
    543 /************************************************************************
    544  *									*
    545  *			Per thread global state handling		*
    546  *									*
    547  ************************************************************************/
    548 
    549 #ifdef LIBXML_THREAD_ENABLED
    550 #ifdef xmlLastError
    551 #undef xmlLastError
    552 #endif
    553 
    554 /**
    555  * xmlFreeGlobalState:
    556  * @state:  a thread global state
    557  *
    558  * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
    559  * global state. It is is used here to reclaim memory resources.
    560  */
    561 static void
    562 xmlFreeGlobalState(void *state)
    563 {
    564     xmlGlobalState *gs = (xmlGlobalState *) state;
    565 
    566     /* free any memory allocated in the thread's xmlLastError */
    567     xmlResetError(&(gs->xmlLastError));
    568     free(state);
    569 }
    570 
    571 /**
    572  * xmlNewGlobalState:
    573  *
    574  * xmlNewGlobalState() allocates a global state. This structure is used to
    575  * hold all data for use by a thread when supporting backwards compatibility
    576  * of libxml2 to pre-thread-safe behaviour.
    577  *
    578  * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
    579  */
    580 static xmlGlobalStatePtr
    581 xmlNewGlobalState(void)
    582 {
    583     xmlGlobalState *gs;
    584 
    585     gs = malloc(sizeof(xmlGlobalState));
    586     if (gs == NULL) {
    587 	xmlGenericError(xmlGenericErrorContext,
    588 			"xmlGetGlobalState: out of memory\n");
    589         return (NULL);
    590     }
    591 
    592     memset(gs, 0, sizeof(xmlGlobalState));
    593     xmlInitializeGlobalState(gs);
    594     return (gs);
    595 }
    596 #endif /* LIBXML_THREAD_ENABLED */
    597 
    598 #ifdef HAVE_PTHREAD_H
    599 #elif defined HAVE_WIN32_THREADS
    600 #if !defined(HAVE_COMPILER_TLS)
    601 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
    602 typedef struct _xmlGlobalStateCleanupHelperParams {
    603     HANDLE thread;
    604     void *memory;
    605 } xmlGlobalStateCleanupHelperParams;
    606 
    607 static void XMLCDECL
    608 xmlGlobalStateCleanupHelper(void *p)
    609 {
    610     xmlGlobalStateCleanupHelperParams *params =
    611         (xmlGlobalStateCleanupHelperParams *) p;
    612     WaitForSingleObject(params->thread, INFINITE);
    613     CloseHandle(params->thread);
    614     xmlFreeGlobalState(params->memory);
    615     free(params);
    616     _endthread();
    617 }
    618 #else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
    619 
    620 typedef struct _xmlGlobalStateCleanupHelperParams {
    621     void *memory;
    622     struct _xmlGlobalStateCleanupHelperParams *prev;
    623     struct _xmlGlobalStateCleanupHelperParams *next;
    624 } xmlGlobalStateCleanupHelperParams;
    625 
    626 static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL;
    627 static CRITICAL_SECTION cleanup_helpers_cs;
    628 
    629 #endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
    630 #endif /* HAVE_COMPILER_TLS */
    631 #endif /* HAVE_WIN32_THREADS */
    632 
    633 #if defined HAVE_BEOS_THREADS
    634 
    635 /**
    636  * xmlGlobalStateCleanup:
    637  * @data: unused parameter
    638  *
    639  * Used for Beos only
    640  */
    641 void
    642 xmlGlobalStateCleanup(void *data)
    643 {
    644     void *globalval = tls_get(globalkey);
    645 
    646     if (globalval != NULL)
    647         xmlFreeGlobalState(globalval);
    648 }
    649 #endif
    650 
    651 /**
    652  * xmlGetGlobalState:
    653  *
    654  * xmlGetGlobalState() is called to retrieve the global state for a thread.
    655  *
    656  * Returns the thread global state or NULL in case of error
    657  */
    658 xmlGlobalStatePtr
    659 xmlGetGlobalState(void)
    660 {
    661 #ifdef HAVE_PTHREAD_H
    662     xmlGlobalState *globalval;
    663 
    664     if (libxml_is_threaded == 0)
    665         return (NULL);
    666 
    667     pthread_once(&once_control, xmlOnceInit);
    668 
    669     if ((globalval = (xmlGlobalState *)
    670          pthread_getspecific(globalkey)) == NULL) {
    671         xmlGlobalState *tsd = xmlNewGlobalState();
    672 	if (tsd == NULL)
    673 	    return(NULL);
    674 
    675         pthread_setspecific(globalkey, tsd);
    676         return (tsd);
    677     }
    678     return (globalval);
    679 #elif defined HAVE_WIN32_THREADS
    680 #if defined(HAVE_COMPILER_TLS)
    681     if (!tlstate_inited) {
    682         tlstate_inited = 1;
    683         xmlInitializeGlobalState(&tlstate);
    684     }
    685     return &tlstate;
    686 #else /* HAVE_COMPILER_TLS */
    687     xmlGlobalState *globalval;
    688     xmlGlobalStateCleanupHelperParams *p;
    689 
    690     xmlOnceInit();
    691 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
    692     globalval = (xmlGlobalState *) TlsGetValue(globalkey);
    693 #else
    694     p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey);
    695     globalval = (xmlGlobalState *) (p ? p->memory : NULL);
    696 #endif
    697     if (globalval == NULL) {
    698         xmlGlobalState *tsd = xmlNewGlobalState();
    699 
    700         if (tsd == NULL)
    701 	    return(NULL);
    702         p = (xmlGlobalStateCleanupHelperParams *)
    703             malloc(sizeof(xmlGlobalStateCleanupHelperParams));
    704 	if (p == NULL) {
    705             xmlGenericError(xmlGenericErrorContext,
    706                             "xmlGetGlobalState: out of memory\n");
    707             xmlFreeGlobalState(tsd);
    708 	    return(NULL);
    709 	}
    710         p->memory = tsd;
    711 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
    712         DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
    713                         GetCurrentProcess(), &p->thread, 0, TRUE,
    714                         DUPLICATE_SAME_ACCESS);
    715         TlsSetValue(globalkey, tsd);
    716         _beginthread(xmlGlobalStateCleanupHelper, 0, p);
    717 #else
    718         EnterCriticalSection(&cleanup_helpers_cs);
    719         if (cleanup_helpers_head != NULL) {
    720             cleanup_helpers_head->prev = p;
    721         }
    722         p->next = cleanup_helpers_head;
    723         p->prev = NULL;
    724         cleanup_helpers_head = p;
    725         TlsSetValue(globalkey, p);
    726         LeaveCriticalSection(&cleanup_helpers_cs);
    727 #endif
    728 
    729         return (tsd);
    730     }
    731     return (globalval);
    732 #endif /* HAVE_COMPILER_TLS */
    733 #elif defined HAVE_BEOS_THREADS
    734     xmlGlobalState *globalval;
    735 
    736     xmlOnceInit();
    737 
    738     if ((globalval = (xmlGlobalState *) tls_get(globalkey)) == NULL) {
    739         xmlGlobalState *tsd = xmlNewGlobalState();
    740 	if (tsd == NULL)
    741 	    return (NULL);
    742 
    743         tls_set(globalkey, tsd);
    744         on_exit_thread(xmlGlobalStateCleanup, NULL);
    745         return (tsd);
    746     }
    747     return (globalval);
    748 #else
    749     return (NULL);
    750 #endif
    751 }
    752 
    753 /************************************************************************
    754  *									*
    755  *			Library wide thread interfaces			*
    756  *									*
    757  ************************************************************************/
    758 
    759 /**
    760  * xmlGetThreadId:
    761  *
    762  * xmlGetThreadId() find the current thread ID number
    763  * Note that this is likely to be broken on some platforms using pthreads
    764  * as the specification doesn't mandate pthread_t to be an integer type
    765  *
    766  * Returns the current thread ID number
    767  */
    768 int
    769 xmlGetThreadId(void)
    770 {
    771 #ifdef HAVE_PTHREAD_H
    772     pthread_t id;
    773     int ret;
    774 
    775     if (libxml_is_threaded == 0)
    776         return (0);
    777     id = pthread_self();
    778     /* horrible but preserves compat, see warning above */
    779     memcpy(&ret, &id, sizeof(ret));
    780     return (ret);
    781 #elif defined HAVE_WIN32_THREADS
    782     return GetCurrentThreadId();
    783 #elif defined HAVE_BEOS_THREADS
    784     return find_thread(NULL);
    785 #else
    786     return ((int) 0);
    787 #endif
    788 }
    789 
    790 /**
    791  * xmlIsMainThread:
    792  *
    793  * xmlIsMainThread() check whether the current thread is the main thread.
    794  *
    795  * Returns 1 if the current thread is the main thread, 0 otherwise
    796  */
    797 int
    798 xmlIsMainThread(void)
    799 {
    800 #ifdef HAVE_PTHREAD_H
    801     if (libxml_is_threaded == -1)
    802         xmlInitThreads();
    803     if (libxml_is_threaded == 0)
    804         return (1);
    805     pthread_once(&once_control, xmlOnceInit);
    806 #elif defined HAVE_WIN32_THREADS
    807     xmlOnceInit();
    808 #elif defined HAVE_BEOS_THREADS
    809     xmlOnceInit();
    810 #endif
    811 
    812 #ifdef DEBUG_THREADS
    813     xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
    814 #endif
    815 #ifdef HAVE_PTHREAD_H
    816     return (pthread_equal(mainthread,pthread_self()));
    817 #elif defined HAVE_WIN32_THREADS
    818     return (mainthread == GetCurrentThreadId());
    819 #elif defined HAVE_BEOS_THREADS
    820     return (mainthread == find_thread(NULL));
    821 #else
    822     return (1);
    823 #endif
    824 }
    825 
    826 /**
    827  * xmlLockLibrary:
    828  *
    829  * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
    830  * library.
    831  */
    832 void
    833 xmlLockLibrary(void)
    834 {
    835 #ifdef DEBUG_THREADS
    836     xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
    837 #endif
    838     xmlRMutexLock(xmlLibraryLock);
    839 }
    840 
    841 /**
    842  * xmlUnlockLibrary:
    843  *
    844  * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
    845  * library.
    846  */
    847 void
    848 xmlUnlockLibrary(void)
    849 {
    850 #ifdef DEBUG_THREADS
    851     xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
    852 #endif
    853     xmlRMutexUnlock(xmlLibraryLock);
    854 }
    855 
    856 /**
    857  * xmlInitThreads:
    858  *
    859  * xmlInitThreads() is used to to initialize all the thread related
    860  * data of the libxml2 library.
    861  */
    862 void
    863 xmlInitThreads(void)
    864 {
    865 #ifdef HAVE_PTHREAD_H
    866     if (libxml_is_threaded == -1) {
    867         if ((pthread_once != NULL) &&
    868             (pthread_getspecific != NULL) &&
    869             (pthread_setspecific != NULL) &&
    870             (pthread_key_create != NULL) &&
    871             (pthread_key_delete != NULL) &&
    872             (pthread_mutex_init != NULL) &&
    873             (pthread_mutex_destroy != NULL) &&
    874             (pthread_mutex_lock != NULL) &&
    875             (pthread_mutex_unlock != NULL) &&
    876             (pthread_cond_init != NULL) &&
    877             (pthread_cond_destroy != NULL) &&
    878             (pthread_cond_wait != NULL) &&
    879             (pthread_equal != NULL) &&
    880             (pthread_self != NULL) &&
    881             (pthread_cond_signal != NULL)) {
    882             libxml_is_threaded = 1;
    883 
    884 /* fprintf(stderr, "Running multithreaded\n"); */
    885         } else {
    886 
    887 /* fprintf(stderr, "Running without multithread\n"); */
    888             libxml_is_threaded = 0;
    889         }
    890     }
    891 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
    892     InitializeCriticalSection(&cleanup_helpers_cs);
    893 #endif
    894 }
    895 
    896 /**
    897  * xmlCleanupThreads:
    898  *
    899  * xmlCleanupThreads() is used to to cleanup all the thread related
    900  * data of the libxml2 library once processing has ended.
    901  *
    902  * WARNING: if your application is multithreaded or has plugin support
    903  *          calling this may crash the application if another thread or
    904  *          a plugin is still using libxml2. It's sometimes very hard to
    905  *          guess if libxml2 is in use in the application, some libraries
    906  *          or plugins may use it without notice. In case of doubt abstain
    907  *          from calling this function or do it just before calling exit()
    908  *          to avoid leak reports from valgrind !
    909  */
    910 void
    911 xmlCleanupThreads(void)
    912 {
    913 #ifdef DEBUG_THREADS
    914     xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
    915 #endif
    916 #ifdef HAVE_PTHREAD_H
    917     if ((libxml_is_threaded)  && (pthread_key_delete != NULL))
    918         pthread_key_delete(globalkey);
    919     once_control = once_control_init;
    920 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
    921     if (globalkey != TLS_OUT_OF_INDEXES) {
    922         xmlGlobalStateCleanupHelperParams *p;
    923 
    924         EnterCriticalSection(&cleanup_helpers_cs);
    925         p = cleanup_helpers_head;
    926         while (p != NULL) {
    927             xmlGlobalStateCleanupHelperParams *temp = p;
    928 
    929             p = p->next;
    930             xmlFreeGlobalState(temp->memory);
    931             free(temp);
    932         }
    933         cleanup_helpers_head = 0;
    934         LeaveCriticalSection(&cleanup_helpers_cs);
    935         TlsFree(globalkey);
    936         globalkey = TLS_OUT_OF_INDEXES;
    937     }
    938     DeleteCriticalSection(&cleanup_helpers_cs);
    939 #endif
    940 }
    941 
    942 #ifdef LIBXML_THREAD_ENABLED
    943 
    944 /**
    945  * xmlOnceInit
    946  *
    947  * xmlOnceInit() is used to initialize the value of mainthread for use
    948  * in other routines. This function should only be called using
    949  * pthread_once() in association with the once_control variable to ensure
    950  * that the function is only called once. See man pthread_once for more
    951  * details.
    952  */
    953 static void
    954 xmlOnceInit(void)
    955 {
    956 #ifdef HAVE_PTHREAD_H
    957     (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
    958     mainthread = pthread_self();
    959     __xmlInitializeDict();
    960 #elif defined(HAVE_WIN32_THREADS)
    961     if (!run_once.done) {
    962         if (InterlockedIncrement(&run_once.control) == 1) {
    963 #if !defined(HAVE_COMPILER_TLS)
    964             globalkey = TlsAlloc();
    965 #endif
    966             mainthread = GetCurrentThreadId();
    967 	    __xmlInitializeDict();
    968             run_once.done = 1;
    969         } else {
    970             /* Another thread is working; give up our slice and
    971              * wait until they're done. */
    972             while (!run_once.done)
    973                 Sleep(0);
    974         }
    975     }
    976 #elif defined HAVE_BEOS_THREADS
    977     if (atomic_add(&run_once_init, 1) == 0) {
    978         globalkey = tls_allocate();
    979         tls_set(globalkey, NULL);
    980         mainthread = find_thread(NULL);
    981 	__xmlInitializeDict();
    982     } else
    983         atomic_add(&run_once_init, -1);
    984 #endif
    985 }
    986 #endif
    987 
    988 /**
    989  * DllMain:
    990  * @hinstDLL: handle to DLL instance
    991  * @fdwReason: Reason code for entry
    992  * @lpvReserved: generic pointer (depends upon reason code)
    993  *
    994  * Entry point for Windows library. It is being used to free thread-specific
    995  * storage.
    996  *
    997  * Returns TRUE always
    998  */
    999 #ifdef HAVE_PTHREAD_H
   1000 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
   1001 #if defined(LIBXML_STATIC_FOR_DLL)
   1002 BOOL XMLCALL
   1003 xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
   1004 #else
   1005 BOOL WINAPI
   1006 DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
   1007 #endif
   1008 {
   1009     switch (fdwReason) {
   1010         case DLL_THREAD_DETACH:
   1011             if (globalkey != TLS_OUT_OF_INDEXES) {
   1012                 xmlGlobalState *globalval = NULL;
   1013                 xmlGlobalStateCleanupHelperParams *p =
   1014                     (xmlGlobalStateCleanupHelperParams *)
   1015                     TlsGetValue(globalkey);
   1016                 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
   1017                 if (globalval) {
   1018                     xmlFreeGlobalState(globalval);
   1019                     TlsSetValue(globalkey, NULL);
   1020                 }
   1021                 if (p) {
   1022                     EnterCriticalSection(&cleanup_helpers_cs);
   1023                     if (p == cleanup_helpers_head)
   1024                         cleanup_helpers_head = p->next;
   1025                     else
   1026                         p->prev->next = p->next;
   1027                     if (p->next != NULL)
   1028                         p->next->prev = p->prev;
   1029                     LeaveCriticalSection(&cleanup_helpers_cs);
   1030                     free(p);
   1031                 }
   1032             }
   1033             break;
   1034     }
   1035     return TRUE;
   1036 }
   1037 #endif
   1038 #define bottom_threads
   1039 #include "elfgcchack.h"
   1040