• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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
xmlNewMutex(void)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
xmlFreeMutex(xmlMutexPtr tok)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
xmlMutexLock(xmlMutexPtr tok)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
xmlMutexUnlock(xmlMutexPtr tok)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
xmlNewRMutex(void)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
xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)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
xmlRMutexLock(xmlRMutexPtr tok)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
xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)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
__xmlGlobalInitMutexLock(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
__xmlGlobalInitMutexUnlock(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
__xmlGlobalInitMutexDestroy(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
xmlFreeGlobalState(void * state)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
xmlNewGlobalState(void)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
xmlGlobalStateCleanupHelper(void * p)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
xmlGlobalStateCleanup(void * data)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
xmlGetGlobalState(void)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
xmlGetThreadId(void)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
xmlIsMainThread(void)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
xmlLockLibrary(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
xmlUnlockLibrary(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
xmlInitThreads(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
xmlCleanupThreads(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
xmlOnceInit(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
xmlDllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)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