include: Move InterlockedExchangeAdd64() definition before its first usage.
[wine.git] / libs / xml2 / threads.c
blob60dbce4c7362031d79fddeae0c4322d70a084aff
1 /**
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>
7 * daniel@veillard.com
8 */
10 #define IN_LIBXML
11 #include "libxml.h"
13 #include <string.h>
14 #include <stdlib.h>
16 #include <libxml/threads.h>
17 #include <libxml/globals.h>
19 #if defined(SOLARIS)
20 #include <note.h>
21 #endif
23 #include "private/dict.h"
24 #include "private/threads.h"
26 /* #define DEBUG_THREADS */
28 #if defined(HAVE_POSIX_THREADS) && \
29 defined(__GLIBC__) && \
30 __GLIBC__ * 100 + __GLIBC_MINOR__ >= 234
33 * The modern way available since glibc 2.32.
35 * The check above is for glibc 2.34 which merged the pthread symbols into
36 * libc. Since we still allow linking without pthread symbols (see below),
37 * this only works if pthread symbols are guaranteed to be available.
40 #include <sys/single_threaded.h>
42 #define XML_IS_THREADED() (!__libc_single_threaded)
43 #define XML_IS_NEVER_THREADED() 0
45 #elif defined(HAVE_POSIX_THREADS) && \
46 defined(__GLIBC__) && \
47 defined(__GNUC__)
50 * The traditional way to check for single-threaded applications with
51 * glibc was to check whether the separate libpthread library is
52 * linked in. This works by not linking libxml2 with libpthread (see
53 * BASE_THREAD_LIBS in configure.ac and Makefile.am) and declaring
54 * pthread functions as weak symbols.
56 * In glibc 2.34, the pthread symbols were moved from libpthread to libc,
57 * so this doesn't work anymore.
59 * At some point, this legacy code and the BASE_THREAD_LIBS hack in
60 * configure.ac can probably be removed.
63 #pragma weak pthread_getspecific
64 #pragma weak pthread_setspecific
65 #pragma weak pthread_key_create
66 #pragma weak pthread_key_delete
67 #pragma weak pthread_mutex_init
68 #pragma weak pthread_mutex_destroy
69 #pragma weak pthread_mutex_lock
70 #pragma weak pthread_mutex_unlock
71 #pragma weak pthread_cond_init
72 #pragma weak pthread_cond_destroy
73 #pragma weak pthread_cond_wait
74 #pragma weak pthread_equal
75 #pragma weak pthread_self
76 #pragma weak pthread_key_create
77 #pragma weak pthread_key_delete
78 #pragma weak pthread_cond_signal
80 #define XML_PTHREAD_WEAK
81 #define XML_IS_THREADED() libxml_is_threaded
82 #define XML_IS_NEVER_THREADED() (!libxml_is_threaded)
84 static int libxml_is_threaded = -1;
86 #else /* other POSIX platforms */
88 #define XML_IS_THREADED() 1
89 #define XML_IS_NEVER_THREADED() 0
91 #endif
94 * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree
95 * to avoid some craziness since xmlMalloc/xmlFree may actually
96 * be hosted on allocated blocks needing them for the allocation ...
100 * xmlRMutex are reentrant mutual exception locks
102 struct _xmlRMutex {
103 #ifdef HAVE_POSIX_THREADS
104 pthread_mutex_t lock;
105 unsigned int held;
106 unsigned int waiters;
107 pthread_t tid;
108 pthread_cond_t cv;
109 #elif defined HAVE_WIN32_THREADS
110 CRITICAL_SECTION cs;
111 #else
112 int empty;
113 #endif
117 * This module still has some internal static data.
118 * - xmlLibraryLock a global lock
119 * - globalkey used for per-thread data
122 #ifdef HAVE_POSIX_THREADS
123 static pthread_key_t globalkey;
124 static pthread_t mainthread;
125 static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
126 #elif defined HAVE_WIN32_THREADS
127 #if defined(HAVE_COMPILER_TLS)
128 static __declspec(thread) xmlGlobalState tlstate;
129 static __declspec(thread) int tlstate_inited = 0;
130 #else /* HAVE_COMPILER_TLS */
131 static DWORD globalkey = TLS_OUT_OF_INDEXES;
132 #endif /* HAVE_COMPILER_TLS */
133 static DWORD mainthread;
134 static volatile LPCRITICAL_SECTION global_init_lock = NULL;
135 #endif
137 static xmlRMutexPtr xmlLibraryLock = NULL;
140 * xmlInitMutex:
141 * @mutex: the mutex
143 * Initialize a mutex.
145 void
146 xmlInitMutex(xmlMutexPtr mutex)
148 #ifdef HAVE_POSIX_THREADS
149 if (XML_IS_NEVER_THREADED() == 0)
150 pthread_mutex_init(&mutex->lock, NULL);
151 #elif defined HAVE_WIN32_THREADS
152 InitializeCriticalSection(&mutex->cs);
153 #else
154 (void) mutex;
155 #endif
159 * xmlNewMutex:
161 * xmlNewMutex() is used to allocate a libxml2 token struct for use in
162 * synchronizing access to data.
164 * Returns a new simple mutex pointer or NULL in case of error
166 xmlMutexPtr
167 xmlNewMutex(void)
169 xmlMutexPtr tok;
171 if ((tok = malloc(sizeof(xmlMutex))) == NULL)
172 return (NULL);
173 xmlInitMutex(tok);
174 return (tok);
178 * xmlCleanupMutex:
179 * @mutex: the simple mutex
181 * Reclaim resources associated with a mutex.
183 void
184 xmlCleanupMutex(xmlMutexPtr mutex)
186 #ifdef HAVE_POSIX_THREADS
187 if (XML_IS_NEVER_THREADED() == 0)
188 pthread_mutex_destroy(&mutex->lock);
189 #elif defined HAVE_WIN32_THREADS
190 DeleteCriticalSection(&mutex->cs);
191 #else
192 (void) mutex;
193 #endif
197 * xmlFreeMutex:
198 * @tok: the simple mutex
200 * Free a mutex.
202 void
203 xmlFreeMutex(xmlMutexPtr tok)
205 if (tok == NULL)
206 return;
208 xmlCleanupMutex(tok);
209 free(tok);
213 * xmlMutexLock:
214 * @tok: the simple mutex
216 * xmlMutexLock() is used to lock a libxml2 token.
218 void
219 xmlMutexLock(xmlMutexPtr tok)
221 if (tok == NULL)
222 return;
223 #ifdef HAVE_POSIX_THREADS
225 * This assumes that __libc_single_threaded won't change while the
226 * lock is held.
228 if (XML_IS_THREADED() != 0)
229 pthread_mutex_lock(&tok->lock);
230 #elif defined HAVE_WIN32_THREADS
231 EnterCriticalSection(&tok->cs);
232 #endif
237 * xmlMutexUnlock:
238 * @tok: the simple mutex
240 * xmlMutexUnlock() is used to unlock a libxml2 token.
242 void
243 xmlMutexUnlock(xmlMutexPtr tok)
245 if (tok == NULL)
246 return;
247 #ifdef HAVE_POSIX_THREADS
248 if (XML_IS_THREADED() != 0)
249 pthread_mutex_unlock(&tok->lock);
250 #elif defined HAVE_WIN32_THREADS
251 LeaveCriticalSection(&tok->cs);
252 #endif
256 * xmlNewRMutex:
258 * xmlRNewMutex() is used to allocate a reentrant mutex for use in
259 * synchronizing access to data. token_r is a re-entrant lock and thus useful
260 * for synchronizing access to data structures that may be manipulated in a
261 * recursive fashion.
263 * Returns the new reentrant mutex pointer or NULL in case of error
265 xmlRMutexPtr
266 xmlNewRMutex(void)
268 xmlRMutexPtr tok;
270 if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
271 return (NULL);
272 #ifdef HAVE_POSIX_THREADS
273 if (XML_IS_NEVER_THREADED() == 0) {
274 pthread_mutex_init(&tok->lock, NULL);
275 tok->held = 0;
276 tok->waiters = 0;
277 pthread_cond_init(&tok->cv, NULL);
279 #elif defined HAVE_WIN32_THREADS
280 InitializeCriticalSection(&tok->cs);
281 #endif
282 return (tok);
286 * xmlFreeRMutex:
287 * @tok: the reentrant mutex
289 * xmlRFreeMutex() is used to reclaim resources associated with a
290 * reentrant mutex.
292 void
293 xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
295 if (tok == NULL)
296 return;
297 #ifdef HAVE_POSIX_THREADS
298 if (XML_IS_NEVER_THREADED() == 0) {
299 pthread_mutex_destroy(&tok->lock);
300 pthread_cond_destroy(&tok->cv);
302 #elif defined HAVE_WIN32_THREADS
303 DeleteCriticalSection(&tok->cs);
304 #endif
305 free(tok);
309 * xmlRMutexLock:
310 * @tok: the reentrant mutex
312 * xmlRMutexLock() is used to lock a libxml2 token_r.
314 void
315 xmlRMutexLock(xmlRMutexPtr tok)
317 if (tok == NULL)
318 return;
319 #ifdef HAVE_POSIX_THREADS
320 if (XML_IS_THREADED() == 0)
321 return;
323 pthread_mutex_lock(&tok->lock);
324 if (tok->held) {
325 if (pthread_equal(tok->tid, pthread_self())) {
326 tok->held++;
327 pthread_mutex_unlock(&tok->lock);
328 return;
329 } else {
330 tok->waiters++;
331 while (tok->held)
332 pthread_cond_wait(&tok->cv, &tok->lock);
333 tok->waiters--;
336 tok->tid = pthread_self();
337 tok->held = 1;
338 pthread_mutex_unlock(&tok->lock);
339 #elif defined HAVE_WIN32_THREADS
340 EnterCriticalSection(&tok->cs);
341 #endif
345 * xmlRMutexUnlock:
346 * @tok: the reentrant mutex
348 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
350 void
351 xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
353 if (tok == NULL)
354 return;
355 #ifdef HAVE_POSIX_THREADS
356 if (XML_IS_THREADED() == 0)
357 return;
359 pthread_mutex_lock(&tok->lock);
360 tok->held--;
361 if (tok->held == 0) {
362 if (tok->waiters)
363 pthread_cond_signal(&tok->cv);
364 memset(&tok->tid, 0, sizeof(tok->tid));
366 pthread_mutex_unlock(&tok->lock);
367 #elif defined HAVE_WIN32_THREADS
368 LeaveCriticalSection(&tok->cs);
369 #endif
373 * xmlGlobalInitMutexLock
375 * Makes sure that the global initialization mutex is initialized and
376 * locks it.
378 void
379 __xmlGlobalInitMutexLock(void)
381 /* Make sure the global init lock is initialized and then lock it. */
382 #ifdef HAVE_POSIX_THREADS
383 #ifdef XML_PTHREAD_WEAK
384 if (pthread_mutex_lock == NULL)
385 return;
386 #else
387 if (XML_IS_THREADED() == 0)
388 return;
389 #endif
390 /* The mutex is statically initialized, so we just lock it. */
391 pthread_mutex_lock(&global_init_lock);
392 #elif defined HAVE_WIN32_THREADS
393 LPCRITICAL_SECTION cs;
395 /* Create a new critical section */
396 if (global_init_lock == NULL) {
397 cs = malloc(sizeof(CRITICAL_SECTION));
398 if (cs == NULL) {
399 xmlGenericError(xmlGenericErrorContext,
400 "xmlGlobalInitMutexLock: out of memory\n");
401 return;
403 InitializeCriticalSection(cs);
405 /* Swap it into the global_init_lock */
406 #ifdef InterlockedCompareExchangePointer
407 InterlockedCompareExchangePointer((void **) &global_init_lock,
408 cs, NULL);
409 #else /* Use older void* version */
410 InterlockedCompareExchange((void **) &global_init_lock,
411 (void *) cs, NULL);
412 #endif /* InterlockedCompareExchangePointer */
414 /* If another thread successfully recorded its critical
415 * section in the global_init_lock then discard the one
416 * allocated by this thread. */
417 if (global_init_lock != cs) {
418 DeleteCriticalSection(cs);
419 free(cs);
423 /* Lock the chosen critical section */
424 EnterCriticalSection(global_init_lock);
425 #endif
428 void
429 __xmlGlobalInitMutexUnlock(void)
431 #ifdef HAVE_POSIX_THREADS
432 #ifdef XML_PTHREAD_WEAK
433 if (pthread_mutex_lock == NULL)
434 return;
435 #else
436 if (XML_IS_THREADED() == 0)
437 return;
438 #endif
439 pthread_mutex_unlock(&global_init_lock);
440 #elif defined HAVE_WIN32_THREADS
441 if (global_init_lock != NULL) {
442 LeaveCriticalSection(global_init_lock);
444 #endif
448 * xmlGlobalInitMutexDestroy
450 * Makes sure that the global initialization mutex is destroyed before
451 * application termination.
453 void
454 __xmlGlobalInitMutexDestroy(void)
456 #ifdef HAVE_POSIX_THREADS
457 #elif defined HAVE_WIN32_THREADS
458 if (global_init_lock != NULL) {
459 DeleteCriticalSection(global_init_lock);
460 free(global_init_lock);
461 global_init_lock = NULL;
463 #endif
466 /************************************************************************
468 * Per thread global state handling *
470 ************************************************************************/
472 #ifdef LIBXML_THREAD_ENABLED
473 #ifdef xmlLastError
474 #undef xmlLastError
475 #endif
478 * xmlFreeGlobalState:
479 * @state: a thread global state
481 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
482 * global state. It is is used here to reclaim memory resources.
484 static void
485 xmlFreeGlobalState(void *state)
487 xmlGlobalState *gs = (xmlGlobalState *) state;
489 /* free any memory allocated in the thread's xmlLastError */
490 xmlResetError(&(gs->xmlLastError));
491 free(state);
495 * xmlNewGlobalState:
497 * xmlNewGlobalState() allocates a global state. This structure is used to
498 * hold all data for use by a thread when supporting backwards compatibility
499 * of libxml2 to pre-thread-safe behaviour.
501 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
503 static xmlGlobalStatePtr
504 xmlNewGlobalState(void)
506 xmlGlobalState *gs;
508 gs = malloc(sizeof(xmlGlobalState));
509 if (gs == NULL) {
510 xmlGenericError(xmlGenericErrorContext,
511 "xmlGetGlobalState: out of memory\n");
512 return (NULL);
515 memset(gs, 0, sizeof(xmlGlobalState));
516 xmlInitializeGlobalState(gs);
517 return (gs);
519 #endif /* LIBXML_THREAD_ENABLED */
521 #ifdef HAVE_POSIX_THREADS
522 #elif defined HAVE_WIN32_THREADS
523 #if !defined(HAVE_COMPILER_TLS)
524 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
525 typedef struct _xmlGlobalStateCleanupHelperParams {
526 HANDLE thread;
527 void *memory;
528 } xmlGlobalStateCleanupHelperParams;
530 static void
531 xmlGlobalStateCleanupHelper(void *p)
533 xmlGlobalStateCleanupHelperParams *params =
534 (xmlGlobalStateCleanupHelperParams *) p;
535 WaitForSingleObject(params->thread, INFINITE);
536 CloseHandle(params->thread);
537 xmlFreeGlobalState(params->memory);
538 free(params);
539 _endthread();
541 #else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
543 typedef struct _xmlGlobalStateCleanupHelperParams {
544 void *memory;
545 struct _xmlGlobalStateCleanupHelperParams *prev;
546 struct _xmlGlobalStateCleanupHelperParams *next;
547 } xmlGlobalStateCleanupHelperParams;
549 static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL;
550 static CRITICAL_SECTION cleanup_helpers_cs;
552 #endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
553 #endif /* HAVE_COMPILER_TLS */
554 #endif /* HAVE_WIN32_THREADS */
557 * xmlGetGlobalState:
559 * DEPRECATED: Internal function, do not use.
561 * xmlGetGlobalState() is called to retrieve the global state for a thread.
563 * Returns the thread global state or NULL in case of error
565 xmlGlobalStatePtr
566 xmlGetGlobalState(void)
568 #ifdef HAVE_POSIX_THREADS
569 xmlGlobalState *globalval;
571 if (XML_IS_THREADED() == 0)
572 return (NULL);
574 if ((globalval = (xmlGlobalState *)
575 pthread_getspecific(globalkey)) == NULL) {
576 xmlGlobalState *tsd = xmlNewGlobalState();
577 if (tsd == NULL)
578 return(NULL);
580 pthread_setspecific(globalkey, tsd);
581 return (tsd);
583 return (globalval);
584 #elif defined HAVE_WIN32_THREADS
585 #if defined(HAVE_COMPILER_TLS)
586 if (!tlstate_inited) {
587 tlstate_inited = 1;
588 xmlInitializeGlobalState(&tlstate);
590 return &tlstate;
591 #else /* HAVE_COMPILER_TLS */
592 xmlGlobalState *globalval;
593 xmlGlobalStateCleanupHelperParams *p;
594 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
595 globalval = (xmlGlobalState *) TlsGetValue(globalkey);
596 #else
597 p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey);
598 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
599 #endif
600 if (globalval == NULL) {
601 xmlGlobalState *tsd = xmlNewGlobalState();
603 if (tsd == NULL)
604 return(NULL);
605 p = (xmlGlobalStateCleanupHelperParams *)
606 malloc(sizeof(xmlGlobalStateCleanupHelperParams));
607 if (p == NULL) {
608 xmlGenericError(xmlGenericErrorContext,
609 "xmlGetGlobalState: out of memory\n");
610 xmlFreeGlobalState(tsd);
611 return(NULL);
613 p->memory = tsd;
614 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
615 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
616 GetCurrentProcess(), &p->thread, 0, TRUE,
617 DUPLICATE_SAME_ACCESS);
618 TlsSetValue(globalkey, tsd);
619 _beginthread(xmlGlobalStateCleanupHelper, 0, p);
620 #else
621 EnterCriticalSection(&cleanup_helpers_cs);
622 if (cleanup_helpers_head != NULL) {
623 cleanup_helpers_head->prev = p;
625 p->next = cleanup_helpers_head;
626 p->prev = NULL;
627 cleanup_helpers_head = p;
628 TlsSetValue(globalkey, p);
629 LeaveCriticalSection(&cleanup_helpers_cs);
630 #endif
632 return (tsd);
634 return (globalval);
635 #endif /* HAVE_COMPILER_TLS */
636 #else
637 return (NULL);
638 #endif
641 /************************************************************************
643 * Library wide thread interfaces *
645 ************************************************************************/
648 * xmlGetThreadId:
650 * DEPRECATED: Internal function, do not use.
652 * xmlGetThreadId() find the current thread ID number
653 * Note that this is likely to be broken on some platforms using pthreads
654 * as the specification doesn't mandate pthread_t to be an integer type
656 * Returns the current thread ID number
659 xmlGetThreadId(void)
661 #ifdef HAVE_POSIX_THREADS
662 pthread_t id;
663 int ret;
665 if (XML_IS_THREADED() == 0)
666 return (0);
667 id = pthread_self();
668 /* horrible but preserves compat, see warning above */
669 memcpy(&ret, &id, sizeof(ret));
670 return (ret);
671 #elif defined HAVE_WIN32_THREADS
672 return GetCurrentThreadId();
673 #else
674 return ((int) 0);
675 #endif
679 * xmlIsMainThread:
681 * DEPRECATED: Internal function, do not use.
683 * xmlIsMainThread() check whether the current thread is the main thread.
685 * Returns 1 if the current thread is the main thread, 0 otherwise
688 xmlIsMainThread(void)
690 xmlInitParser();
692 #ifdef DEBUG_THREADS
693 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
694 #endif
695 #ifdef HAVE_POSIX_THREADS
696 if (XML_IS_THREADED() == 0)
697 return (1);
698 return (pthread_equal(mainthread,pthread_self()));
699 #elif defined HAVE_WIN32_THREADS
700 return (mainthread == GetCurrentThreadId());
701 #else
702 return (1);
703 #endif
707 * xmlLockLibrary:
709 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
710 * library.
712 void
713 xmlLockLibrary(void)
715 #ifdef DEBUG_THREADS
716 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
717 #endif
718 xmlRMutexLock(xmlLibraryLock);
722 * xmlUnlockLibrary:
724 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
725 * library.
727 void
728 xmlUnlockLibrary(void)
730 #ifdef DEBUG_THREADS
731 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
732 #endif
733 xmlRMutexUnlock(xmlLibraryLock);
737 * xmlInitThreads:
739 * DEPRECATED: Alias for xmlInitParser.
741 void
742 xmlInitThreads(void)
744 xmlInitParser();
748 * xmlInitThreadsInternal:
750 * Used to to initialize all the thread related data.
752 void
753 xmlInitThreadsInternal(void)
755 #ifdef HAVE_POSIX_THREADS
756 #ifdef XML_PTHREAD_WEAK
758 * This is somewhat unreliable since libpthread could be loaded
759 * later with dlopen() and threads could be created. But it's
760 * long-standing behavior and hard to work around.
762 if (libxml_is_threaded == -1)
763 libxml_is_threaded =
764 (pthread_getspecific != NULL) &&
765 (pthread_setspecific != NULL) &&
766 (pthread_key_create != NULL) &&
767 (pthread_key_delete != NULL) &&
768 (pthread_mutex_init != NULL) &&
769 (pthread_mutex_destroy != NULL) &&
770 (pthread_mutex_lock != NULL) &&
771 (pthread_mutex_unlock != NULL) &&
772 (pthread_cond_init != NULL) &&
773 (pthread_cond_destroy != NULL) &&
774 (pthread_cond_wait != NULL) &&
776 * pthread_equal can be inline, resuting in -Waddress warnings.
777 * Let's assume it's available if all the other functions are.
779 /* (pthread_equal != NULL) && */
780 (pthread_self != NULL) &&
781 (pthread_cond_signal != NULL);
782 if (libxml_is_threaded == 0)
783 return;
784 #endif /* XML_PTHREAD_WEAK */
785 pthread_key_create(&globalkey, xmlFreeGlobalState);
786 mainthread = pthread_self();
787 #elif defined(HAVE_WIN32_THREADS)
788 #if !defined(HAVE_COMPILER_TLS)
789 #if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)
790 InitializeCriticalSection(&cleanup_helpers_cs);
791 #endif
792 globalkey = TlsAlloc();
793 #endif
794 mainthread = GetCurrentThreadId();
795 #endif
799 * xmlCleanupThreads:
801 * DEPRECATED: This function is a no-op. Call xmlCleanupParser
802 * to free global state but see the warnings there. xmlCleanupParser
803 * should be only called once at program exit. In most cases, you don't
804 * have call cleanup functions at all.
806 void
807 xmlCleanupThreads(void)
812 * xmlCleanupThreadsInternal:
814 * Used to to cleanup all the thread related data.
816 void
817 xmlCleanupThreadsInternal(void)
819 #ifdef HAVE_POSIX_THREADS
820 #ifdef XML_PTHREAD_WEAK
821 if (libxml_is_threaded == 0)
822 return;
823 #endif /* XML_PTHREAD_WEAK */
824 pthread_key_delete(globalkey);
825 #elif defined(HAVE_WIN32_THREADS)
826 #if !defined(HAVE_COMPILER_TLS)
827 if (globalkey != TLS_OUT_OF_INDEXES) {
828 #if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)
829 xmlGlobalStateCleanupHelperParams *p;
831 EnterCriticalSection(&cleanup_helpers_cs);
832 p = cleanup_helpers_head;
833 while (p != NULL) {
834 xmlGlobalStateCleanupHelperParams *temp = p;
836 p = p->next;
837 xmlFreeGlobalState(temp->memory);
838 free(temp);
840 cleanup_helpers_head = 0;
841 LeaveCriticalSection(&cleanup_helpers_cs);
842 #endif
843 TlsFree(globalkey);
844 globalkey = TLS_OUT_OF_INDEXES;
846 #if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)
847 DeleteCriticalSection(&cleanup_helpers_cs);
848 #endif
849 #endif
850 #endif
854 * DllMain:
855 * @hinstDLL: handle to DLL instance
856 * @fdwReason: Reason code for entry
857 * @lpvReserved: generic pointer (depends upon reason code)
859 * Entry point for Windows library. It is being used to free thread-specific
860 * storage.
862 * Returns TRUE always
864 #ifdef HAVE_POSIX_THREADS
865 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
866 #if defined(LIBXML_STATIC_FOR_DLL)
868 xmlDllMain(ATTRIBUTE_UNUSED void *hinstDLL, unsigned long fdwReason,
869 ATTRIBUTE_UNUSED void *lpvReserved)
870 #else
871 /* declare to avoid "no previous prototype for 'DllMain'" warning */
872 /* Note that we do NOT want to include this function declaration in
873 a public header because it's meant to be called by Windows itself,
874 not a program that uses this library. This also has to be exported. */
876 XMLPUBFUN BOOL WINAPI
877 DllMain (HINSTANCE hinstDLL,
878 DWORD fdwReason,
879 LPVOID lpvReserved);
881 BOOL WINAPI
882 DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL, DWORD fdwReason,
883 ATTRIBUTE_UNUSED LPVOID lpvReserved)
884 #endif
886 switch (fdwReason) {
887 case DLL_THREAD_DETACH:
888 if (globalkey != TLS_OUT_OF_INDEXES) {
889 xmlGlobalState *globalval = NULL;
890 xmlGlobalStateCleanupHelperParams *p =
891 (xmlGlobalStateCleanupHelperParams *)
892 TlsGetValue(globalkey);
893 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
894 if (globalval) {
895 xmlFreeGlobalState(globalval);
896 TlsSetValue(globalkey, NULL);
898 if (p) {
899 EnterCriticalSection(&cleanup_helpers_cs);
900 if (p == cleanup_helpers_head)
901 cleanup_helpers_head = p->next;
902 else
903 p->prev->next = p->next;
904 if (p->next != NULL)
905 p->next->prev = p->prev;
906 LeaveCriticalSection(&cleanup_helpers_cs);
907 free(p);
910 break;
912 return TRUE;
914 #endif