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