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