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
31 //#include <windows.h>
32 #ifndef HAVE_COMPILER_TLS
37 #ifdef HAVE_BEOS_THREADS
46 /* #define DEBUG_THREADS */
50 #if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 303) && \
51 defined(__GLIBC__) && defined(__linux__)
53 static int libxml_is_threaded
= -1;
55 #define XML_PTHREAD_WEAK
57 #pragma weak pthread_once
58 #pragma weak pthread_getspecific
59 #pragma weak pthread_setspecific
60 #pragma weak pthread_key_create
61 #pragma weak pthread_key_delete
62 #pragma weak pthread_mutex_init
63 #pragma weak pthread_mutex_destroy
64 #pragma weak pthread_mutex_lock
65 #pragma weak pthread_mutex_unlock
66 #pragma weak pthread_cond_init
67 #pragma weak pthread_cond_destroy
68 #pragma weak pthread_cond_wait
69 #pragma weak pthread_equal
70 #pragma weak pthread_self
71 #pragma weak pthread_key_create
72 #pragma weak pthread_key_delete
73 #pragma weak pthread_cond_signal
75 #else /* __GNUC__, __GLIBC__, __linux__ */
77 static int libxml_is_threaded
= 1;
79 #endif /* __GNUC__, __GLIBC__, __linux__ */
81 #endif /* HAVE_PTHREAD_H */
84 * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree
85 * to avoid some crazyness since xmlMalloc/xmlFree may actually
86 * be hosted on allocated blocks needing them for the allocation ...
90 * xmlMutex are a simple mutual exception locks
95 #elif defined HAVE_WIN32_THREADS
97 #elif defined HAVE_BEOS_THREADS
106 * xmlRMutex are reentrant mutual exception locks
109 #ifdef HAVE_PTHREAD_H
110 pthread_mutex_t lock
;
112 unsigned int waiters
;
115 #elif defined HAVE_WIN32_THREADS
118 #elif defined HAVE_BEOS_THREADS
128 * This module still has some internal static data.
129 * - xmlLibraryLock a global lock
130 * - globalkey used for per-thread data
133 #ifdef HAVE_PTHREAD_H
134 static pthread_key_t globalkey
;
135 static pthread_t mainthread
;
136 static pthread_once_t once_control
= PTHREAD_ONCE_INIT
;
137 static pthread_once_t once_control_init
= PTHREAD_ONCE_INIT
;
138 static pthread_mutex_t global_init_lock
= PTHREAD_MUTEX_INITIALIZER
;
139 #elif defined HAVE_WIN32_THREADS
140 #if defined(HAVE_COMPILER_TLS)
141 static __declspec(thread
) xmlGlobalState tlstate
;
142 static __declspec(thread
) int tlstate_inited
= 0;
143 #else /* HAVE_COMPILER_TLS */
144 static DWORD globalkey
= TLS_OUT_OF_INDEXES
;
145 #endif /* HAVE_COMPILER_TLS */
146 static DWORD mainthread
;
150 } run_once
= { 0, 0};
151 static volatile LPCRITICAL_SECTION global_init_lock
= NULL
;
153 /* endif HAVE_WIN32_THREADS */
154 #elif defined HAVE_BEOS_THREADS
156 thread_id mainthread
= 0;
157 int32 run_once_init
= 0;
158 static int32 global_init_lock
= -1;
159 static vint32 global_init_count
= 0;
162 static xmlRMutexPtr xmlLibraryLock
= NULL
;
164 #ifdef LIBXML_THREAD_ENABLED
165 static void xmlOnceInit(void);
171 * xmlNewMutex() is used to allocate a libxml2 token struct for use in
172 * synchronizing access to data.
174 * Returns a new simple mutex pointer or NULL in case of error
181 if ((tok
= malloc(sizeof(xmlMutex
))) == NULL
)
183 #ifdef HAVE_PTHREAD_H
184 if (libxml_is_threaded
!= 0)
185 pthread_mutex_init(&tok
->lock
, NULL
);
186 #elif defined HAVE_WIN32_THREADS
187 tok
->mutex
= CreateMutex(NULL
, FALSE
, NULL
);
188 #elif defined HAVE_BEOS_THREADS
189 if ((tok
->sem
= create_sem(1, "xmlMutex")) < B_OK
) {
200 * @tok: the simple mutex
202 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
206 xmlFreeMutex(xmlMutexPtr tok
)
211 #ifdef HAVE_PTHREAD_H
212 if (libxml_is_threaded
!= 0)
213 pthread_mutex_destroy(&tok
->lock
);
214 #elif defined HAVE_WIN32_THREADS
215 CloseHandle(tok
->mutex
);
216 #elif defined HAVE_BEOS_THREADS
217 delete_sem(tok
->sem
);
224 * @tok: the simple mutex
226 * xmlMutexLock() is used to lock a libxml2 token.
229 xmlMutexLock(xmlMutexPtr tok
)
233 #ifdef HAVE_PTHREAD_H
234 if (libxml_is_threaded
!= 0)
235 pthread_mutex_lock(&tok
->lock
);
236 #elif defined HAVE_WIN32_THREADS
237 WaitForSingleObject(tok
->mutex
, INFINITE
);
238 #elif defined HAVE_BEOS_THREADS
239 if (acquire_sem(tok
->sem
) != B_NO_ERROR
) {
241 xmlGenericError(xmlGenericErrorContext
,
242 "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
245 tok
->tid
= find_thread(NULL
);
252 * @tok: the simple mutex
254 * xmlMutexUnlock() is used to unlock a libxml2 token.
257 xmlMutexUnlock(xmlMutexPtr tok
)
261 #ifdef HAVE_PTHREAD_H
262 if (libxml_is_threaded
!= 0)
263 pthread_mutex_unlock(&tok
->lock
);
264 #elif defined HAVE_WIN32_THREADS
265 ReleaseMutex(tok
->mutex
);
266 #elif defined HAVE_BEOS_THREADS
267 if (tok
->tid
== find_thread(NULL
)) {
269 release_sem(tok
->sem
);
277 * xmlRNewMutex() is used to allocate a reentrant mutex for use in
278 * synchronizing access to data. token_r is a re-entrant lock and thus useful
279 * for synchronizing access to data structures that may be manipulated in a
282 * Returns the new reentrant mutex pointer or NULL in case of error
289 if ((tok
= malloc(sizeof(xmlRMutex
))) == NULL
)
291 #ifdef HAVE_PTHREAD_H
292 if (libxml_is_threaded
!= 0) {
293 pthread_mutex_init(&tok
->lock
, NULL
);
296 pthread_cond_init(&tok
->cv
, NULL
);
298 #elif defined HAVE_WIN32_THREADS
299 InitializeCriticalSection(&tok
->cs
);
301 #elif defined HAVE_BEOS_THREADS
302 if ((tok
->lock
= xmlNewMutex()) == NULL
) {
313 * @tok: the reentrant mutex
315 * xmlRFreeMutex() is used to reclaim resources associated with a
319 xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED
)
323 #ifdef HAVE_PTHREAD_H
324 if (libxml_is_threaded
!= 0) {
325 pthread_mutex_destroy(&tok
->lock
);
326 pthread_cond_destroy(&tok
->cv
);
328 #elif defined HAVE_WIN32_THREADS
329 DeleteCriticalSection(&tok
->cs
);
330 #elif defined HAVE_BEOS_THREADS
331 xmlFreeMutex(tok
->lock
);
338 * @tok: the reentrant mutex
340 * xmlRMutexLock() is used to lock a libxml2 token_r.
343 xmlRMutexLock(xmlRMutexPtr tok
)
347 #ifdef HAVE_PTHREAD_H
348 if (libxml_is_threaded
== 0)
351 pthread_mutex_lock(&tok
->lock
);
353 if (pthread_equal(tok
->tid
, pthread_self())) {
355 pthread_mutex_unlock(&tok
->lock
);
360 pthread_cond_wait(&tok
->cv
, &tok
->lock
);
364 tok
->tid
= pthread_self();
366 pthread_mutex_unlock(&tok
->lock
);
367 #elif defined HAVE_WIN32_THREADS
368 EnterCriticalSection(&tok
->cs
);
370 #elif defined HAVE_BEOS_THREADS
371 if (tok
->lock
->tid
== find_thread(NULL
)) {
375 xmlMutexLock(tok
->lock
);
383 * @tok: the reentrant mutex
385 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
388 xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED
)
392 #ifdef HAVE_PTHREAD_H
393 if (libxml_is_threaded
== 0)
396 pthread_mutex_lock(&tok
->lock
);
398 if (tok
->held
== 0) {
400 pthread_cond_signal(&tok
->cv
);
401 memset(&tok
->tid
, 0, sizeof(tok
->tid
));
403 pthread_mutex_unlock(&tok
->lock
);
404 #elif defined HAVE_WIN32_THREADS
405 if (tok
->count
> 0) {
407 LeaveCriticalSection(&tok
->cs
);
409 #elif defined HAVE_BEOS_THREADS
410 if (tok
->lock
->tid
== find_thread(NULL
)) {
412 if (tok
->count
== 0) {
413 xmlMutexUnlock(tok
->lock
);
421 * xmlGlobalInitMutexLock
423 * Makes sure that the global initialization mutex is initialized and
427 __xmlGlobalInitMutexLock(void)
429 /* Make sure the global init lock is initialized and then lock it. */
430 #ifdef HAVE_PTHREAD_H
431 /* The mutex is statically initialized, so we just lock it. */
432 #ifdef XML_PTHREAD_WEAK
433 if (pthread_mutex_lock
== NULL
)
435 #endif /* XML_PTHREAD_WEAK */
436 pthread_mutex_lock(&global_init_lock
);
437 #elif defined HAVE_WIN32_THREADS
438 LPCRITICAL_SECTION cs
;
440 /* Create a new critical section */
441 if (global_init_lock
== NULL
) {
442 cs
= malloc(sizeof(CRITICAL_SECTION
));
444 xmlGenericError(xmlGenericErrorContext
,
445 "xmlGlobalInitMutexLock: out of memory\n");
448 InitializeCriticalSection(cs
);
450 /* Swap it into the global_init_lock */
451 #ifdef InterlockedCompareExchangePointer
452 InterlockedCompareExchangePointer((void **) &global_init_lock
,
454 #else /* Use older void* version */
455 InterlockedCompareExchange((void **) &global_init_lock
,
457 #endif /* InterlockedCompareExchangePointer */
459 /* If another thread successfully recorded its critical
460 * section in the global_init_lock then discard the one
461 * allocated by this thread. */
462 if (global_init_lock
!= cs
) {
463 DeleteCriticalSection(cs
);
468 /* Lock the chosen critical section */
469 EnterCriticalSection(global_init_lock
);
470 #elif defined HAVE_BEOS_THREADS
473 /* Allocate a new semaphore */
474 sem
= create_sem(1, "xmlGlobalinitMutex");
476 while (global_init_lock
== -1) {
477 if (atomic_add(&global_init_count
, 1) == 0) {
478 global_init_lock
= sem
;
481 atomic_add(&global_init_count
, -1);
485 /* If another thread successfully recorded its critical
486 * section in the global_init_lock then discard the one
487 * allocated by this thread. */
488 if (global_init_lock
!= sem
)
491 /* Acquire the chosen semaphore */
492 if (acquire_sem(global_init_lock
) != B_NO_ERROR
) {
494 xmlGenericError(xmlGenericErrorContext
,
495 "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n");
502 __xmlGlobalInitMutexUnlock(void)
504 #ifdef HAVE_PTHREAD_H
505 #ifdef XML_PTHREAD_WEAK
506 if (pthread_mutex_unlock
== NULL
)
508 #endif /* XML_PTHREAD_WEAK */
509 pthread_mutex_unlock(&global_init_lock
);
510 #elif defined HAVE_WIN32_THREADS
511 if (global_init_lock
!= NULL
) {
512 LeaveCriticalSection(global_init_lock
);
514 #elif defined HAVE_BEOS_THREADS
515 release_sem(global_init_lock
);
520 * xmlGlobalInitMutexDestroy
522 * Makes sure that the global initialization mutex is destroyed before
523 * application termination.
526 __xmlGlobalInitMutexDestroy(void)
528 #ifdef HAVE_PTHREAD_H
529 #elif defined HAVE_WIN32_THREADS
530 if (global_init_lock
!= NULL
) {
531 DeleteCriticalSection(global_init_lock
);
532 free(global_init_lock
);
533 global_init_lock
= NULL
;
538 /************************************************************************
540 * Per thread global state handling *
542 ************************************************************************/
544 #ifdef LIBXML_THREAD_ENABLED
550 * xmlFreeGlobalState:
551 * @state: a thread global state
553 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
554 * global state. It is is used here to reclaim memory resources.
557 xmlFreeGlobalState(void *state
)
559 xmlGlobalState
*gs
= (xmlGlobalState
*) state
;
561 /* free any memory allocated in the thread's xmlLastError */
562 xmlResetError(&(gs
->xmlLastError
));
569 * xmlNewGlobalState() allocates a global state. This structure is used to
570 * hold all data for use by a thread when supporting backwards compatibility
571 * of libxml2 to pre-thread-safe behaviour.
573 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
575 static xmlGlobalStatePtr
576 xmlNewGlobalState(void)
580 gs
= malloc(sizeof(xmlGlobalState
));
582 xmlGenericError(xmlGenericErrorContext
,
583 "xmlGetGlobalState: out of memory\n");
587 memset(gs
, 0, sizeof(xmlGlobalState
));
588 xmlInitializeGlobalState(gs
);
591 #endif /* LIBXML_THREAD_ENABLED */
593 #ifdef HAVE_PTHREAD_H
594 #elif defined HAVE_WIN32_THREADS
595 #if !defined(HAVE_COMPILER_TLS)
596 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
597 typedef struct _xmlGlobalStateCleanupHelperParams
{
600 } xmlGlobalStateCleanupHelperParams
;
603 xmlGlobalStateCleanupHelper(void *p
)
605 xmlGlobalStateCleanupHelperParams
*params
=
606 (xmlGlobalStateCleanupHelperParams
*) p
;
607 WaitForSingleObject(params
->thread
, INFINITE
);
608 CloseHandle(params
->thread
);
609 xmlFreeGlobalState(params
->memory
);
613 #else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
615 typedef struct _xmlGlobalStateCleanupHelperParams
{
617 struct _xmlGlobalStateCleanupHelperParams
*prev
;
618 struct _xmlGlobalStateCleanupHelperParams
*next
;
619 } xmlGlobalStateCleanupHelperParams
;
621 static xmlGlobalStateCleanupHelperParams
*cleanup_helpers_head
= NULL
;
622 static CRITICAL_SECTION cleanup_helpers_cs
;
624 #endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
625 #endif /* HAVE_COMPILER_TLS */
626 #endif /* HAVE_WIN32_THREADS */
628 #if defined HAVE_BEOS_THREADS
631 * xmlGlobalStateCleanup:
632 * @data: unused parameter
637 xmlGlobalStateCleanup(void *data
)
639 void *globalval
= tls_get(globalkey
);
641 if (globalval
!= NULL
)
642 xmlFreeGlobalState(globalval
);
649 * xmlGetGlobalState() is called to retrieve the global state for a thread.
651 * Returns the thread global state or NULL in case of error
654 xmlGetGlobalState(void)
656 #ifdef HAVE_PTHREAD_H
657 xmlGlobalState
*globalval
;
659 if (libxml_is_threaded
== 0)
662 pthread_once(&once_control
, xmlOnceInit
);
664 if ((globalval
= (xmlGlobalState
*)
665 pthread_getspecific(globalkey
)) == NULL
) {
666 xmlGlobalState
*tsd
= xmlNewGlobalState();
670 pthread_setspecific(globalkey
, tsd
);
674 #elif defined HAVE_WIN32_THREADS
675 #if defined(HAVE_COMPILER_TLS)
676 if (!tlstate_inited
) {
678 xmlInitializeGlobalState(&tlstate
);
681 #else /* HAVE_COMPILER_TLS */
682 xmlGlobalState
*globalval
;
683 xmlGlobalStateCleanupHelperParams
*p
;
686 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
687 globalval
= (xmlGlobalState
*) TlsGetValue(globalkey
);
689 p
= (xmlGlobalStateCleanupHelperParams
*) TlsGetValue(globalkey
);
690 globalval
= (xmlGlobalState
*) (p
? p
->memory
: NULL
);
692 if (globalval
== NULL
) {
693 xmlGlobalState
*tsd
= xmlNewGlobalState();
697 p
= (xmlGlobalStateCleanupHelperParams
*)
698 malloc(sizeof(xmlGlobalStateCleanupHelperParams
));
700 xmlGenericError(xmlGenericErrorContext
,
701 "xmlGetGlobalState: out of memory\n");
702 xmlFreeGlobalState(tsd
);
706 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
707 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
708 GetCurrentProcess(), &p
->thread
, 0, TRUE
,
709 DUPLICATE_SAME_ACCESS
);
710 TlsSetValue(globalkey
, tsd
);
711 _beginthread(xmlGlobalStateCleanupHelper
, 0, p
);
713 EnterCriticalSection(&cleanup_helpers_cs
);
714 if (cleanup_helpers_head
!= NULL
) {
715 cleanup_helpers_head
->prev
= p
;
717 p
->next
= cleanup_helpers_head
;
719 cleanup_helpers_head
= p
;
720 TlsSetValue(globalkey
, p
);
721 LeaveCriticalSection(&cleanup_helpers_cs
);
727 #endif /* HAVE_COMPILER_TLS */
728 #elif defined HAVE_BEOS_THREADS
729 xmlGlobalState
*globalval
;
733 if ((globalval
= (xmlGlobalState
*) tls_get(globalkey
)) == NULL
) {
734 xmlGlobalState
*tsd
= xmlNewGlobalState();
738 tls_set(globalkey
, tsd
);
739 on_exit_thread(xmlGlobalStateCleanup
, NULL
);
748 /************************************************************************
750 * Library wide thread interfaces *
752 ************************************************************************/
757 * xmlGetThreadId() find the current thread ID number
758 * Note that this is likely to be broken on some platforms using pthreads
759 * as the specification doesn't mandate pthread_t to be an integer type
761 * Returns the current thread ID number
766 #ifdef HAVE_PTHREAD_H
770 if (libxml_is_threaded
== 0)
773 /* horrible but preserves compat, see warning above */
774 memcpy(&ret
, &id
, sizeof(ret
));
776 #elif defined HAVE_WIN32_THREADS
777 return GetCurrentThreadId();
778 #elif defined HAVE_BEOS_THREADS
779 return find_thread(NULL
);
788 * xmlIsMainThread() check whether the current thread is the main thread.
790 * Returns 1 if the current thread is the main thread, 0 otherwise
793 xmlIsMainThread(void)
795 #ifdef HAVE_PTHREAD_H
796 if (libxml_is_threaded
== -1)
798 if (libxml_is_threaded
== 0)
800 pthread_once(&once_control
, xmlOnceInit
);
801 #elif defined HAVE_WIN32_THREADS
803 #elif defined HAVE_BEOS_THREADS
808 xmlGenericError(xmlGenericErrorContext
, "xmlIsMainThread()\n");
810 #ifdef HAVE_PTHREAD_H
811 return (pthread_equal(mainthread
,pthread_self()));
812 #elif defined HAVE_WIN32_THREADS
813 return (mainthread
== GetCurrentThreadId());
814 #elif defined HAVE_BEOS_THREADS
815 return (mainthread
== find_thread(NULL
));
824 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
831 xmlGenericError(xmlGenericErrorContext
, "xmlLockLibrary()\n");
833 xmlRMutexLock(xmlLibraryLock
);
839 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
843 xmlUnlockLibrary(void)
846 xmlGenericError(xmlGenericErrorContext
, "xmlUnlockLibrary()\n");
848 xmlRMutexUnlock(xmlLibraryLock
);
854 * xmlInitThreads() is used to to initialize all the thread related
855 * data of the libxml2 library.
860 #ifdef HAVE_PTHREAD_H
861 #ifdef XML_PTHREAD_WEAK
862 if (libxml_is_threaded
== -1) {
863 if ((pthread_once
!= NULL
) &&
864 (pthread_getspecific
!= NULL
) &&
865 (pthread_setspecific
!= NULL
) &&
866 (pthread_key_create
!= NULL
) &&
867 (pthread_key_delete
!= NULL
) &&
868 (pthread_mutex_init
!= NULL
) &&
869 (pthread_mutex_destroy
!= NULL
) &&
870 (pthread_mutex_lock
!= NULL
) &&
871 (pthread_mutex_unlock
!= NULL
) &&
872 (pthread_cond_init
!= NULL
) &&
873 (pthread_cond_destroy
!= NULL
) &&
874 (pthread_cond_wait
!= NULL
) &&
875 (pthread_equal
!= NULL
) &&
876 (pthread_self
!= NULL
) &&
877 (pthread_cond_signal
!= NULL
)) {
878 libxml_is_threaded
= 1;
880 /* fprintf(stderr, "Running multithreaded\n"); */
883 /* fprintf(stderr, "Running without multithread\n"); */
884 libxml_is_threaded
= 0;
887 #endif /* XML_PTHREAD_WEAK */
888 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
889 InitializeCriticalSection(&cleanup_helpers_cs
);
896 * xmlCleanupThreads() is used to to cleanup all the thread related
897 * data of the libxml2 library once processing has ended.
899 * WARNING: if your application is multithreaded or has plugin support
900 * calling this may crash the application if another thread or
901 * a plugin is still using libxml2. It's sometimes very hard to
902 * guess if libxml2 is in use in the application, some libraries
903 * or plugins may use it without notice. In case of doubt abstain
904 * from calling this function or do it just before calling exit()
905 * to avoid leak reports from valgrind !
908 xmlCleanupThreads(void)
911 xmlGenericError(xmlGenericErrorContext
, "xmlCleanupThreads()\n");
913 #ifdef HAVE_PTHREAD_H
914 if (libxml_is_threaded
!= 0)
915 pthread_key_delete(globalkey
);
916 once_control
= once_control_init
;
917 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
918 if (globalkey
!= TLS_OUT_OF_INDEXES
) {
919 xmlGlobalStateCleanupHelperParams
*p
;
921 EnterCriticalSection(&cleanup_helpers_cs
);
922 p
= cleanup_helpers_head
;
924 xmlGlobalStateCleanupHelperParams
*temp
= p
;
927 xmlFreeGlobalState(temp
->memory
);
930 cleanup_helpers_head
= 0;
931 LeaveCriticalSection(&cleanup_helpers_cs
);
933 globalkey
= TLS_OUT_OF_INDEXES
;
935 DeleteCriticalSection(&cleanup_helpers_cs
);
939 #ifdef LIBXML_THREAD_ENABLED
944 * xmlOnceInit() is used to initialize the value of mainthread for use
945 * in other routines. This function should only be called using
946 * pthread_once() in association with the once_control variable to ensure
947 * that the function is only called once. See man pthread_once for more
953 #ifdef HAVE_PTHREAD_H
954 (void) pthread_key_create(&globalkey
, xmlFreeGlobalState
);
955 mainthread
= pthread_self();
956 __xmlInitializeDict();
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();
963 mainthread
= GetCurrentThreadId();
964 __xmlInitializeDict();
967 /* Another thread is working; give up our slice and
968 * wait until they're done. */
969 while (!run_once
.done
)
973 #elif defined HAVE_BEOS_THREADS
974 if (atomic_add(&run_once_init
, 1) == 0) {
975 globalkey
= tls_allocate();
976 tls_set(globalkey
, NULL
);
977 mainthread
= find_thread(NULL
);
978 __xmlInitializeDict();
980 atomic_add(&run_once_init
, -1);
987 * @hinstDLL: handle to DLL instance
988 * @fdwReason: Reason code for entry
989 * @lpvReserved: generic pointer (depends upon reason code)
991 * Entry point for Windows library. It is being used to free thread-specific
994 * Returns TRUE always
996 #ifdef HAVE_PTHREAD_H
997 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
998 #if defined(LIBXML_STATIC_FOR_DLL)
1000 xmlDllMain(ATTRIBUTE_UNUSED
void *hinstDLL
, unsigned long fdwReason
,
1001 ATTRIBUTE_UNUSED
void *lpvReserved
)
1003 /* declare to avoid "no previous prototype for 'DllMain'" warning */
1004 /* Note that we do NOT want to include this function declaration in
1005 a public header because it's meant to be called by Windows itself,
1006 not a program that uses this library. This also has to be exported. */
1008 XMLPUBFUN BOOL WINAPI
1009 DllMain (HINSTANCE hinstDLL
,
1011 LPVOID lpvReserved
);
1014 DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL
, DWORD fdwReason
,
1015 ATTRIBUTE_UNUSED LPVOID lpvReserved
)
1018 switch (fdwReason
) {
1019 case DLL_THREAD_DETACH
:
1020 if (globalkey
!= TLS_OUT_OF_INDEXES
) {
1021 xmlGlobalState
*globalval
= NULL
;
1022 xmlGlobalStateCleanupHelperParams
*p
=
1023 (xmlGlobalStateCleanupHelperParams
*)
1024 TlsGetValue(globalkey
);
1025 globalval
= (xmlGlobalState
*) (p
? p
->memory
: NULL
);
1027 xmlFreeGlobalState(globalval
);
1028 TlsSetValue(globalkey
, NULL
);
1031 EnterCriticalSection(&cleanup_helpers_cs
);
1032 if (p
== cleanup_helpers_head
)
1033 cleanup_helpers_head
= p
->next
;
1035 p
->prev
->next
= p
->next
;
1036 if (p
->next
!= NULL
)
1037 p
->next
->prev
= p
->prev
;
1038 LeaveCriticalSection(&cleanup_helpers_cs
);
1047 #define bottom_threads
1048 #include "elfgcchack.h"