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