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