2 * threads.c: set of generic threading related routines
4 * See Copyright for the status of this software.
6 * Gary Pennington <Gary.Pennington@uk.sun.com>
15 #include <libxml/threads.h>
16 #include <libxml/globals.h>
18 #ifdef HAVE_SYS_TYPES_H
19 #include <sys/types.h>
29 #elif defined HAVE_WIN32_THREADS
30 #define WIN32_LEAN_AND_MEAN
32 #ifndef HAVE_COMPILER_TLS
37 #ifdef HAVE_BEOS_THREADS
46 /* #define DEBUG_THREADS */
50 static int libxml_is_threaded = -1;
51 #if defined(__GNUC__) && defined(__GLIBC__)
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
72 #endif /* __linux__ */
73 #endif /* defined(__GNUC__) && defined(__GLIBC__) */
74 #endif /* HAVE_PTHREAD_H */
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 ...
83 * xmlMutex are a simple mutual exception locks
88 #elif defined HAVE_WIN32_THREADS
90 #elif defined HAVE_BEOS_THREADS
99 * xmlRMutex are reentrant mutual exception locks
102 #ifdef HAVE_PTHREAD_H
103 pthread_mutex_t lock;
105 unsigned int waiters;
108 #elif defined HAVE_WIN32_THREADS
111 #elif defined HAVE_BEOS_THREADS
121 * This module still has some internal static data.
122 * - xmlLibraryLock a global lock
123 * - globalkey used for per-thread data
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;
143 } run_once = { 0, 0};
144 static volatile LPCRITICAL_SECTION global_init_lock = NULL;
146 /* endif HAVE_WIN32_THREADS */
147 #elif defined HAVE_BEOS_THREADS
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;
155 static xmlRMutexPtr xmlLibraryLock = NULL;
157 #ifdef LIBXML_THREAD_ENABLED
158 static void xmlOnceInit(void);
164 * xmlNewMutex() is used to allocate a libxml2 token struct for use in
165 * synchronizing access to data.
167 * Returns a new simple mutex pointer or NULL in case of error
174 if ((tok = malloc(sizeof(xmlMutex))) == 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) {
193 * @tok: the simple mutex
195 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
199 xmlFreeMutex(xmlMutexPtr tok)
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);
217 * @tok: the simple mutex
219 * xmlMutexLock() is used to lock a libxml2 token.
222 xmlMutexLock(xmlMutexPtr tok)
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) {
234 xmlGenericError(xmlGenericErrorContext,
235 "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
238 tok->tid = find_thread(NULL);
245 * @tok: the simple mutex
247 * xmlMutexUnlock() is used to unlock a libxml2 token.
250 xmlMutexUnlock(xmlMutexPtr tok)
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)) {
262 release_sem(tok->sem);
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
275 * Returns the new reentrant mutex pointer or NULL in case of error
282 if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
284 #ifdef HAVE_PTHREAD_H
285 if (libxml_is_threaded != 0) {
286 pthread_mutex_init(&tok->lock, NULL);
289 pthread_cond_init(&tok->cv, NULL);
291 #elif defined HAVE_WIN32_THREADS
292 InitializeCriticalSection(&tok->cs);
294 #elif defined HAVE_BEOS_THREADS
295 if ((tok->lock = xmlNewMutex()) == NULL) {
306 * @tok: the reentrant mutex
308 * xmlRFreeMutex() is used to reclaim resources associated with a
312 xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
316 #ifdef HAVE_PTHREAD_H
317 if (libxml_is_threaded != 0) {
318 pthread_mutex_destroy(&tok->lock);
319 pthread_cond_destroy(&tok->cv);
321 #elif defined HAVE_WIN32_THREADS
322 DeleteCriticalSection(&tok->cs);
323 #elif defined HAVE_BEOS_THREADS
324 xmlFreeMutex(tok->lock);
331 * @tok: the reentrant mutex
333 * xmlRMutexLock() is used to lock a libxml2 token_r.
336 xmlRMutexLock(xmlRMutexPtr tok)
340 #ifdef HAVE_PTHREAD_H
341 if (libxml_is_threaded == 0)
344 pthread_mutex_lock(&tok->lock);
346 if (pthread_equal(tok->tid, pthread_self())) {
348 pthread_mutex_unlock(&tok->lock);
353 pthread_cond_wait(&tok->cv, &tok->lock);
357 tok->tid = pthread_self();
359 pthread_mutex_unlock(&tok->lock);
360 #elif defined HAVE_WIN32_THREADS
361 EnterCriticalSection(&tok->cs);
363 #elif defined HAVE_BEOS_THREADS
364 if (tok->lock->tid == find_thread(NULL)) {
368 xmlMutexLock(tok->lock);
376 * @tok: the reentrant mutex
378 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
381 xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
385 #ifdef HAVE_PTHREAD_H
386 if (libxml_is_threaded == 0)
389 pthread_mutex_lock(&tok->lock);
391 if (tok->held == 0) {
393 pthread_cond_signal(&tok->cv);
394 memset(&tok->tid, 0, sizeof(tok->tid));
396 pthread_mutex_unlock(&tok->lock);
397 #elif defined HAVE_WIN32_THREADS
398 if (tok->count > 0) {
400 LeaveCriticalSection(&tok->cs);
402 #elif defined HAVE_BEOS_THREADS
403 if (tok->lock->tid == find_thread(NULL)) {
405 if (tok->count == 0) {
406 xmlMutexUnlock(tok->lock);
414 * xmlGlobalInitMutexLock
416 * Makes sure that the global initialization mutex is initialized and
420 __xmlGlobalInitMutexLock(void)
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;
430 /* Create a new critical section */
431 if (global_init_lock == NULL) {
432 cs = malloc(sizeof(CRITICAL_SECTION));
434 xmlGenericError(xmlGenericErrorContext,
435 "xmlGlobalInitMutexLock: out of memory\n");
438 InitializeCriticalSection(cs);
440 /* Swap it into the global_init_lock */
441 #ifdef InterlockedCompareExchangePointer
442 InterlockedCompareExchangePointer((void **) &global_init_lock,
444 #else /* Use older void* version */
445 InterlockedCompareExchange((void **) &global_init_lock,
447 #endif /* InterlockedCompareExchangePointer */
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);
458 /* Lock the chosen critical section */
459 EnterCriticalSection(global_init_lock);
460 #elif defined HAVE_BEOS_THREADS
463 /* Allocate a new semaphore */
464 sem = create_sem(1, "xmlGlobalinitMutex");
466 while (global_init_lock == -1) {
467 if (atomic_add(&global_init_count, 1) == 0) {
468 global_init_lock = sem;
471 atomic_add(&global_init_count, -1);
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)
481 /* Acquire the chosen semaphore */
482 if (acquire_sem(global_init_lock) != B_NO_ERROR) {
484 xmlGenericError(xmlGenericErrorContext,
485 "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n");
492 __xmlGlobalInitMutexUnlock(void)
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);
501 #elif defined HAVE_BEOS_THREADS
502 release_sem(global_init_lock);
507 * xmlGlobalInitMutexDestroy
509 * Makes sure that the global initialization mutex is destroyed before
510 * application termination.
513 __xmlGlobalInitMutexDestroy(void)
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;
525 /************************************************************************
527 * Per thread global state handling *
529 ************************************************************************/
531 #ifdef LIBXML_THREAD_ENABLED
537 * xmlFreeGlobalState:
538 * @state: a thread global state
540 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
541 * global state. It is is used here to reclaim memory resources.
544 xmlFreeGlobalState(void *state)
546 xmlGlobalState *gs = (xmlGlobalState *) state;
548 /* free any memory allocated in the thread's xmlLastError */
549 xmlResetError(&(gs->xmlLastError));
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.
560 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
562 static xmlGlobalStatePtr
563 xmlNewGlobalState(void)
567 gs = malloc(sizeof(xmlGlobalState));
569 xmlGenericError(xmlGenericErrorContext,
570 "xmlGetGlobalState: out of memory\n");
574 memset(gs, 0, sizeof(xmlGlobalState));
575 xmlInitializeGlobalState(gs);
578 #endif /* LIBXML_THREAD_ENABLED */
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 {
587 } xmlGlobalStateCleanupHelperParams;
590 xmlGlobalStateCleanupHelper(void *p)
592 xmlGlobalStateCleanupHelperParams *params =
593 (xmlGlobalStateCleanupHelperParams *) p;
594 WaitForSingleObject(params->thread, INFINITE);
595 CloseHandle(params->thread);
596 xmlFreeGlobalState(params->memory);
600 #else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
602 typedef struct _xmlGlobalStateCleanupHelperParams {
604 struct _xmlGlobalStateCleanupHelperParams *prev;
605 struct _xmlGlobalStateCleanupHelperParams *next;
606 } xmlGlobalStateCleanupHelperParams;
608 static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL;
609 static CRITICAL_SECTION cleanup_helpers_cs;
611 #endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
612 #endif /* HAVE_COMPILER_TLS */
613 #endif /* HAVE_WIN32_THREADS */
615 #if defined HAVE_BEOS_THREADS
618 * xmlGlobalStateCleanup:
619 * @data: unused parameter
624 xmlGlobalStateCleanup(void *data)
626 void *globalval = tls_get(globalkey);
628 if (globalval != NULL)
629 xmlFreeGlobalState(globalval);
636 * xmlGetGlobalState() is called to retrieve the global state for a thread.
638 * Returns the thread global state or NULL in case of error
641 xmlGetGlobalState(void)
643 #ifdef HAVE_PTHREAD_H
644 xmlGlobalState *globalval;
646 if (libxml_is_threaded == 0)
649 pthread_once(&once_control, xmlOnceInit);
651 if ((globalval = (xmlGlobalState *)
652 pthread_getspecific(globalkey)) == NULL) {
653 xmlGlobalState *tsd = xmlNewGlobalState();
657 pthread_setspecific(globalkey, tsd);
661 #elif defined HAVE_WIN32_THREADS
662 #if defined(HAVE_COMPILER_TLS)
663 if (!tlstate_inited) {
665 xmlInitializeGlobalState(&tlstate);
668 #else /* HAVE_COMPILER_TLS */
669 xmlGlobalState *globalval;
670 xmlGlobalStateCleanupHelperParams *p;
673 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
674 globalval = (xmlGlobalState *) TlsGetValue(globalkey);
676 p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey);
677 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
679 if (globalval == NULL) {
680 xmlGlobalState *tsd = xmlNewGlobalState();
684 p = (xmlGlobalStateCleanupHelperParams *)
685 malloc(sizeof(xmlGlobalStateCleanupHelperParams));
687 xmlGenericError(xmlGenericErrorContext,
688 "xmlGetGlobalState: out of memory\n");
689 xmlFreeGlobalState(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);
700 EnterCriticalSection(&cleanup_helpers_cs);
701 if (cleanup_helpers_head != NULL) {
702 cleanup_helpers_head->prev = p;
704 p->next = cleanup_helpers_head;
706 cleanup_helpers_head = p;
707 TlsSetValue(globalkey, p);
708 LeaveCriticalSection(&cleanup_helpers_cs);
714 #endif /* HAVE_COMPILER_TLS */
715 #elif defined HAVE_BEOS_THREADS
716 xmlGlobalState *globalval;
720 if ((globalval = (xmlGlobalState *) tls_get(globalkey)) == NULL) {
721 xmlGlobalState *tsd = xmlNewGlobalState();
725 tls_set(globalkey, tsd);
726 on_exit_thread(xmlGlobalStateCleanup, NULL);
735 /************************************************************************
737 * Library wide thread interfaces *
739 ************************************************************************/
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
748 * Returns the current thread ID number
753 #ifdef HAVE_PTHREAD_H
757 if (libxml_is_threaded == 0)
760 /* horrible but preserves compat, see warning above */
761 memcpy(&ret, &id, sizeof(ret));
763 #elif defined HAVE_WIN32_THREADS
764 return GetCurrentThreadId();
765 #elif defined HAVE_BEOS_THREADS
766 return find_thread(NULL);
775 * xmlIsMainThread() check whether the current thread is the main thread.
777 * Returns 1 if the current thread is the main thread, 0 otherwise
780 xmlIsMainThread(void)
782 #ifdef HAVE_PTHREAD_H
783 if (libxml_is_threaded == -1)
785 if (libxml_is_threaded == 0)
787 pthread_once(&once_control, xmlOnceInit);
788 #elif defined HAVE_WIN32_THREADS
790 #elif defined HAVE_BEOS_THREADS
795 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
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));
811 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
818 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
820 xmlRMutexLock(xmlLibraryLock);
826 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
830 xmlUnlockLibrary(void)
833 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
835 xmlRMutexUnlock(xmlLibraryLock);
841 * xmlInitThreads() is used to to initialize all the thread related
842 * data of the libxml2 library.
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;
866 /* fprintf(stderr, "Running multithreaded\n"); */
869 /* fprintf(stderr, "Running without multithread\n"); */
870 libxml_is_threaded = 0;
873 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
874 InitializeCriticalSection(&cleanup_helpers_cs);
881 * xmlCleanupThreads() is used to to cleanup all the thread related
882 * data of the libxml2 library once processing has ended.
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 !
893 xmlCleanupThreads(void)
896 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
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;
906 EnterCriticalSection(&cleanup_helpers_cs);
907 p = cleanup_helpers_head;
909 xmlGlobalStateCleanupHelperParams *temp = p;
912 xmlFreeGlobalState(temp->memory);
915 cleanup_helpers_head = 0;
916 LeaveCriticalSection(&cleanup_helpers_cs);
918 globalkey = TLS_OUT_OF_INDEXES;
920 DeleteCriticalSection(&cleanup_helpers_cs);
924 #ifdef LIBXML_THREAD_ENABLED
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
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();
948 mainthread = GetCurrentThreadId();
949 __xmlInitializeDict();
952 /* Another thread is working; give up our slice and
953 * wait until they're done. */
954 while (!run_once.done)
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();
965 atomic_add(&run_once_init, -1);
972 * @hinstDLL: handle to DLL instance
973 * @fdwReason: Reason code for entry
974 * @lpvReserved: generic pointer (depends upon reason code)
976 * Entry point for Windows library. It is being used to free thread-specific
979 * Returns TRUE always
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)
985 xmlDllMain(ATTRIBUTE_UNUSED void *hinstDLL, unsigned long fdwReason,
986 ATTRIBUTE_UNUSED void *lpvReserved)
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. */
993 XMLPUBFUN BOOL WINAPI
994 DllMain (HINSTANCE hinstDLL,
999 DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL, DWORD fdwReason,
1000 ATTRIBUTE_UNUSED LPVOID lpvReserved)
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);
1012 xmlFreeGlobalState(globalval);
1013 TlsSetValue(globalkey, NULL);
1016 EnterCriticalSection(&cleanup_helpers_cs);
1017 if (p == cleanup_helpers_head)
1018 cleanup_helpers_head = p->next;
1020 p->prev->next = p->next;
1021 if (p->next != NULL)
1022 p->next->prev = p->prev;
1023 LeaveCriticalSection(&cleanup_helpers_cs);
1032 #define bottom_threads
1033 #include "elfgcchack.h"