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