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