winegstreamer: Pass desired input queue length to wg_transform_create.
[wine.git] / libs / xml2 / threads.c
blobf462ebf258eb6cf51fd56e574a0d824e82922c51
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 #ifdef HAVE_PTHREAD_H
20 #include <pthread.h>
21 #elif defined HAVE_WIN32_THREADS
22 #define WIN32_LEAN_AND_MEAN
23 #include <windows.h>
24 #ifndef HAVE_COMPILER_TLS
25 #include <process.h>
26 #endif
27 #endif
29 #ifdef HAVE_BEOS_THREADS
30 #include <OS.h>
31 #include <TLS.h>
32 #endif
34 #if defined(SOLARIS)
35 #include <note.h>
36 #endif
38 /* #define DEBUG_THREADS */
40 #ifdef HAVE_PTHREAD_H
42 #if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 303) && \
43 defined(__GLIBC__) && defined(__linux__)
45 static int libxml_is_threaded = -1;
47 #define XML_PTHREAD_WEAK
49 #pragma weak pthread_once
50 #pragma weak pthread_getspecific
51 #pragma weak pthread_setspecific
52 #pragma weak pthread_key_create
53 #pragma weak pthread_key_delete
54 #pragma weak pthread_mutex_init
55 #pragma weak pthread_mutex_destroy
56 #pragma weak pthread_mutex_lock
57 #pragma weak pthread_mutex_unlock
58 #pragma weak pthread_cond_init
59 #pragma weak pthread_cond_destroy
60 #pragma weak pthread_cond_wait
61 #pragma weak pthread_equal
62 #pragma weak pthread_self
63 #pragma weak pthread_key_create
64 #pragma weak pthread_key_delete
65 #pragma weak pthread_cond_signal
67 #else /* __GNUC__, __GLIBC__, __linux__ */
69 static int libxml_is_threaded = 1;
71 #endif /* __GNUC__, __GLIBC__, __linux__ */
73 #endif /* HAVE_PTHREAD_H */
76 * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree
77 * to avoid some craziness since xmlMalloc/xmlFree may actually
78 * be hosted on allocated blocks needing them for the allocation ...
82 * xmlMutex are a simple mutual exception locks
84 struct _xmlMutex {
85 #ifdef HAVE_PTHREAD_H
86 pthread_mutex_t lock;
87 #elif defined HAVE_WIN32_THREADS
88 CRITICAL_SECTION cs;
89 #elif defined HAVE_BEOS_THREADS
90 sem_id sem;
91 thread_id tid;
92 #else
93 int empty;
94 #endif
98 * xmlRMutex are reentrant mutual exception locks
100 struct _xmlRMutex {
101 #ifdef HAVE_PTHREAD_H
102 pthread_mutex_t lock;
103 unsigned int held;
104 unsigned int waiters;
105 pthread_t tid;
106 pthread_cond_t cv;
107 #elif defined HAVE_WIN32_THREADS
108 CRITICAL_SECTION cs;
109 #elif defined HAVE_BEOS_THREADS
110 xmlMutexPtr lock;
111 thread_id tid;
112 int32 count;
113 #else
114 int empty;
115 #endif
119 * This module still has some internal static data.
120 * - xmlLibraryLock a global lock
121 * - globalkey used for per-thread data
124 #ifdef HAVE_PTHREAD_H
125 static pthread_key_t globalkey;
126 static pthread_t mainthread;
127 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
128 static pthread_once_t once_control_init = PTHREAD_ONCE_INIT;
129 static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
130 #elif defined HAVE_WIN32_THREADS
131 #if defined(HAVE_COMPILER_TLS)
132 static __declspec(thread) xmlGlobalState tlstate;
133 static __declspec(thread) int tlstate_inited = 0;
134 #else /* HAVE_COMPILER_TLS */
135 static DWORD globalkey = TLS_OUT_OF_INDEXES;
136 #endif /* HAVE_COMPILER_TLS */
137 static DWORD mainthread;
138 static struct {
139 DWORD done;
140 LONG control;
141 } run_once = { 0, 0};
142 static volatile LPCRITICAL_SECTION global_init_lock = NULL;
144 /* endif HAVE_WIN32_THREADS */
145 #elif defined HAVE_BEOS_THREADS
146 int32 globalkey = 0;
147 thread_id mainthread = 0;
148 int32 run_once_init = 0;
149 static int32 global_init_lock = -1;
150 static vint32 global_init_count = 0;
151 #endif
153 static xmlRMutexPtr xmlLibraryLock = NULL;
155 #ifdef LIBXML_THREAD_ENABLED
156 static void xmlOnceInit(void);
157 #endif
160 * xmlNewMutex:
162 * xmlNewMutex() is used to allocate a libxml2 token struct for use in
163 * synchronizing access to data.
165 * Returns a new simple mutex pointer or NULL in case of error
167 xmlMutexPtr
168 xmlNewMutex(void)
170 xmlMutexPtr tok;
172 if ((tok = malloc(sizeof(xmlMutex))) == NULL)
173 return (NULL);
174 #ifdef HAVE_PTHREAD_H
175 if (libxml_is_threaded != 0)
176 pthread_mutex_init(&tok->lock, NULL);
177 #elif defined HAVE_WIN32_THREADS
178 InitializeCriticalSection(&tok->cs);
179 #elif defined HAVE_BEOS_THREADS
180 if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) {
181 free(tok);
182 return NULL;
184 tok->tid = -1;
185 #endif
186 return (tok);
190 * xmlFreeMutex:
191 * @tok: the simple mutex
193 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
194 * struct.
196 void
197 xmlFreeMutex(xmlMutexPtr tok)
199 if (tok == NULL)
200 return;
202 #ifdef HAVE_PTHREAD_H
203 if (libxml_is_threaded != 0)
204 pthread_mutex_destroy(&tok->lock);
205 #elif defined HAVE_WIN32_THREADS
206 DeleteCriticalSection(&tok->cs);
207 #elif defined HAVE_BEOS_THREADS
208 delete_sem(tok->sem);
209 #endif
210 free(tok);
214 * xmlMutexLock:
215 * @tok: the simple mutex
217 * xmlMutexLock() is used to lock a libxml2 token.
219 void
220 xmlMutexLock(xmlMutexPtr tok)
222 if (tok == NULL)
223 return;
224 #ifdef HAVE_PTHREAD_H
225 if (libxml_is_threaded != 0)
226 pthread_mutex_lock(&tok->lock);
227 #elif defined HAVE_WIN32_THREADS
228 EnterCriticalSection(&tok->cs);
229 #elif defined HAVE_BEOS_THREADS
230 if (acquire_sem(tok->sem) != B_NO_ERROR) {
231 #ifdef DEBUG_THREADS
232 xmlGenericError(xmlGenericErrorContext,
233 "xmlMutexLock():BeOS:Couldn't acquire semaphore\n");
234 #endif
236 tok->tid = find_thread(NULL);
237 #endif
242 * xmlMutexUnlock:
243 * @tok: the simple mutex
245 * xmlMutexUnlock() is used to unlock a libxml2 token.
247 void
248 xmlMutexUnlock(xmlMutexPtr tok)
250 if (tok == NULL)
251 return;
252 #ifdef HAVE_PTHREAD_H
253 if (libxml_is_threaded != 0)
254 pthread_mutex_unlock(&tok->lock);
255 #elif defined HAVE_WIN32_THREADS
256 LeaveCriticalSection(&tok->cs);
257 #elif defined HAVE_BEOS_THREADS
258 if (tok->tid == find_thread(NULL)) {
259 tok->tid = -1;
260 release_sem(tok->sem);
262 #endif
266 * xmlNewRMutex:
268 * xmlRNewMutex() is used to allocate a reentrant mutex for use in
269 * synchronizing access to data. token_r is a re-entrant lock and thus useful
270 * for synchronizing access to data structures that may be manipulated in a
271 * recursive fashion.
273 * Returns the new reentrant mutex pointer or NULL in case of error
275 xmlRMutexPtr
276 xmlNewRMutex(void)
278 xmlRMutexPtr tok;
280 if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
281 return (NULL);
282 #ifdef HAVE_PTHREAD_H
283 if (libxml_is_threaded != 0) {
284 pthread_mutex_init(&tok->lock, NULL);
285 tok->held = 0;
286 tok->waiters = 0;
287 pthread_cond_init(&tok->cv, NULL);
289 #elif defined HAVE_WIN32_THREADS
290 InitializeCriticalSection(&tok->cs);
291 #elif defined HAVE_BEOS_THREADS
292 if ((tok->lock = xmlNewMutex()) == NULL) {
293 free(tok);
294 return NULL;
296 tok->count = 0;
297 #endif
298 return (tok);
302 * xmlFreeRMutex:
303 * @tok: the reentrant mutex
305 * xmlRFreeMutex() is used to reclaim resources associated with a
306 * reentrant mutex.
308 void
309 xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
311 if (tok == NULL)
312 return;
313 #ifdef HAVE_PTHREAD_H
314 if (libxml_is_threaded != 0) {
315 pthread_mutex_destroy(&tok->lock);
316 pthread_cond_destroy(&tok->cv);
318 #elif defined HAVE_WIN32_THREADS
319 DeleteCriticalSection(&tok->cs);
320 #elif defined HAVE_BEOS_THREADS
321 xmlFreeMutex(tok->lock);
322 #endif
323 free(tok);
327 * xmlRMutexLock:
328 * @tok: the reentrant mutex
330 * xmlRMutexLock() is used to lock a libxml2 token_r.
332 void
333 xmlRMutexLock(xmlRMutexPtr tok)
335 if (tok == NULL)
336 return;
337 #ifdef HAVE_PTHREAD_H
338 if (libxml_is_threaded == 0)
339 return;
341 pthread_mutex_lock(&tok->lock);
342 if (tok->held) {
343 if (pthread_equal(tok->tid, pthread_self())) {
344 tok->held++;
345 pthread_mutex_unlock(&tok->lock);
346 return;
347 } else {
348 tok->waiters++;
349 while (tok->held)
350 pthread_cond_wait(&tok->cv, &tok->lock);
351 tok->waiters--;
354 tok->tid = pthread_self();
355 tok->held = 1;
356 pthread_mutex_unlock(&tok->lock);
357 #elif defined HAVE_WIN32_THREADS
358 EnterCriticalSection(&tok->cs);
359 #elif defined HAVE_BEOS_THREADS
360 if (tok->lock->tid == find_thread(NULL)) {
361 tok->count++;
362 return;
363 } else {
364 xmlMutexLock(tok->lock);
365 tok->count = 1;
367 #endif
371 * xmlRMutexUnlock:
372 * @tok: the reentrant mutex
374 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
376 void
377 xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
379 if (tok == NULL)
380 return;
381 #ifdef HAVE_PTHREAD_H
382 if (libxml_is_threaded == 0)
383 return;
385 pthread_mutex_lock(&tok->lock);
386 tok->held--;
387 if (tok->held == 0) {
388 if (tok->waiters)
389 pthread_cond_signal(&tok->cv);
390 memset(&tok->tid, 0, sizeof(tok->tid));
392 pthread_mutex_unlock(&tok->lock);
393 #elif defined HAVE_WIN32_THREADS
394 LeaveCriticalSection(&tok->cs);
395 #elif defined HAVE_BEOS_THREADS
396 if (tok->lock->tid == find_thread(NULL)) {
397 tok->count--;
398 if (tok->count == 0) {
399 xmlMutexUnlock(tok->lock);
401 return;
403 #endif
407 * xmlGlobalInitMutexLock
409 * Makes sure that the global initialization mutex is initialized and
410 * locks it.
412 void
413 __xmlGlobalInitMutexLock(void)
415 /* Make sure the global init lock is initialized and then lock it. */
416 #ifdef HAVE_PTHREAD_H
417 /* The mutex is statically initialized, so we just lock it. */
418 #ifdef XML_PTHREAD_WEAK
419 if (pthread_mutex_lock == NULL)
420 return;
421 #endif /* XML_PTHREAD_WEAK */
422 pthread_mutex_lock(&global_init_lock);
423 #elif defined HAVE_WIN32_THREADS
424 LPCRITICAL_SECTION cs;
426 /* Create a new critical section */
427 if (global_init_lock == NULL) {
428 cs = malloc(sizeof(CRITICAL_SECTION));
429 if (cs == NULL) {
430 xmlGenericError(xmlGenericErrorContext,
431 "xmlGlobalInitMutexLock: out of memory\n");
432 return;
434 InitializeCriticalSection(cs);
436 /* Swap it into the global_init_lock */
437 #ifdef InterlockedCompareExchangePointer
438 InterlockedCompareExchangePointer((void **) &global_init_lock,
439 cs, NULL);
440 #else /* Use older void* version */
441 InterlockedCompareExchange((void **) &global_init_lock,
442 (void *) cs, NULL);
443 #endif /* InterlockedCompareExchangePointer */
445 /* If another thread successfully recorded its critical
446 * section in the global_init_lock then discard the one
447 * allocated by this thread. */
448 if (global_init_lock != cs) {
449 DeleteCriticalSection(cs);
450 free(cs);
454 /* Lock the chosen critical section */
455 EnterCriticalSection(global_init_lock);
456 #elif defined HAVE_BEOS_THREADS
457 int32 sem;
459 /* Allocate a new semaphore */
460 sem = create_sem(1, "xmlGlobalinitMutex");
462 while (global_init_lock == -1) {
463 if (atomic_add(&global_init_count, 1) == 0) {
464 global_init_lock = sem;
465 } else {
466 snooze(1);
467 atomic_add(&global_init_count, -1);
471 /* If another thread successfully recorded its critical
472 * section in the global_init_lock then discard the one
473 * allocated by this thread. */
474 if (global_init_lock != sem)
475 delete_sem(sem);
477 /* Acquire the chosen semaphore */
478 if (acquire_sem(global_init_lock) != B_NO_ERROR) {
479 #ifdef DEBUG_THREADS
480 xmlGenericError(xmlGenericErrorContext,
481 "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n");
482 #endif
484 #endif
487 void
488 __xmlGlobalInitMutexUnlock(void)
490 #ifdef HAVE_PTHREAD_H
491 #ifdef XML_PTHREAD_WEAK
492 if (pthread_mutex_unlock == NULL)
493 return;
494 #endif /* XML_PTHREAD_WEAK */
495 pthread_mutex_unlock(&global_init_lock);
496 #elif defined HAVE_WIN32_THREADS
497 if (global_init_lock != NULL) {
498 LeaveCriticalSection(global_init_lock);
500 #elif defined HAVE_BEOS_THREADS
501 release_sem(global_init_lock);
502 #endif
506 * xmlGlobalInitMutexDestroy
508 * Makes sure that the global initialization mutex is destroyed before
509 * application termination.
511 void
512 __xmlGlobalInitMutexDestroy(void)
514 #ifdef HAVE_PTHREAD_H
515 #elif defined HAVE_WIN32_THREADS
516 if (global_init_lock != NULL) {
517 DeleteCriticalSection(global_init_lock);
518 free(global_init_lock);
519 global_init_lock = NULL;
521 #endif
524 /************************************************************************
526 * Per thread global state handling *
528 ************************************************************************/
530 #ifdef LIBXML_THREAD_ENABLED
531 #ifdef xmlLastError
532 #undef xmlLastError
533 #endif
536 * xmlFreeGlobalState:
537 * @state: a thread global state
539 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
540 * global state. It is is used here to reclaim memory resources.
542 static void
543 xmlFreeGlobalState(void *state)
545 xmlGlobalState *gs = (xmlGlobalState *) state;
547 /* free any memory allocated in the thread's xmlLastError */
548 xmlResetError(&(gs->xmlLastError));
549 free(state);
553 * xmlNewGlobalState:
555 * xmlNewGlobalState() allocates a global state. This structure is used to
556 * hold all data for use by a thread when supporting backwards compatibility
557 * of libxml2 to pre-thread-safe behaviour.
559 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
561 static xmlGlobalStatePtr
562 xmlNewGlobalState(void)
564 xmlGlobalState *gs;
566 gs = malloc(sizeof(xmlGlobalState));
567 if (gs == NULL) {
568 xmlGenericError(xmlGenericErrorContext,
569 "xmlGetGlobalState: out of memory\n");
570 return (NULL);
573 memset(gs, 0, sizeof(xmlGlobalState));
574 xmlInitializeGlobalState(gs);
575 return (gs);
577 #endif /* LIBXML_THREAD_ENABLED */
579 #ifdef HAVE_PTHREAD_H
580 #elif defined HAVE_WIN32_THREADS
581 #if !defined(HAVE_COMPILER_TLS)
582 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
583 typedef struct _xmlGlobalStateCleanupHelperParams {
584 HANDLE thread;
585 void *memory;
586 } xmlGlobalStateCleanupHelperParams;
588 static void XMLCDECL
589 xmlGlobalStateCleanupHelper(void *p)
591 xmlGlobalStateCleanupHelperParams *params =
592 (xmlGlobalStateCleanupHelperParams *) p;
593 WaitForSingleObject(params->thread, INFINITE);
594 CloseHandle(params->thread);
595 xmlFreeGlobalState(params->memory);
596 free(params);
597 _endthread();
599 #else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
601 typedef struct _xmlGlobalStateCleanupHelperParams {
602 void *memory;
603 struct _xmlGlobalStateCleanupHelperParams *prev;
604 struct _xmlGlobalStateCleanupHelperParams *next;
605 } xmlGlobalStateCleanupHelperParams;
607 static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL;
608 static CRITICAL_SECTION cleanup_helpers_cs;
610 #endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
611 #endif /* HAVE_COMPILER_TLS */
612 #endif /* HAVE_WIN32_THREADS */
614 #if defined HAVE_BEOS_THREADS
617 * xmlGlobalStateCleanup:
618 * @data: unused parameter
620 * Used for Beos only
622 void
623 xmlGlobalStateCleanup(void *data)
625 void *globalval = tls_get(globalkey);
627 if (globalval != NULL)
628 xmlFreeGlobalState(globalval);
630 #endif
633 * xmlGetGlobalState:
635 * xmlGetGlobalState() is called to retrieve the global state for a thread.
637 * Returns the thread global state or NULL in case of error
639 xmlGlobalStatePtr
640 xmlGetGlobalState(void)
642 #ifdef HAVE_PTHREAD_H
643 xmlGlobalState *globalval;
645 if (libxml_is_threaded == 0)
646 return (NULL);
648 pthread_once(&once_control, xmlOnceInit);
650 if ((globalval = (xmlGlobalState *)
651 pthread_getspecific(globalkey)) == NULL) {
652 xmlGlobalState *tsd = xmlNewGlobalState();
653 if (tsd == NULL)
654 return(NULL);
656 pthread_setspecific(globalkey, tsd);
657 return (tsd);
659 return (globalval);
660 #elif defined HAVE_WIN32_THREADS
661 #if defined(HAVE_COMPILER_TLS)
662 if (!tlstate_inited) {
663 tlstate_inited = 1;
664 xmlInitializeGlobalState(&tlstate);
666 return &tlstate;
667 #else /* HAVE_COMPILER_TLS */
668 xmlGlobalState *globalval;
669 xmlGlobalStateCleanupHelperParams *p;
671 xmlOnceInit();
672 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
673 globalval = (xmlGlobalState *) TlsGetValue(globalkey);
674 #else
675 p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey);
676 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
677 #endif
678 if (globalval == NULL) {
679 xmlGlobalState *tsd = xmlNewGlobalState();
681 if (tsd == NULL)
682 return(NULL);
683 p = (xmlGlobalStateCleanupHelperParams *)
684 malloc(sizeof(xmlGlobalStateCleanupHelperParams));
685 if (p == NULL) {
686 xmlGenericError(xmlGenericErrorContext,
687 "xmlGetGlobalState: out of memory\n");
688 xmlFreeGlobalState(tsd);
689 return(NULL);
691 p->memory = tsd;
692 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
693 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
694 GetCurrentProcess(), &p->thread, 0, TRUE,
695 DUPLICATE_SAME_ACCESS);
696 TlsSetValue(globalkey, tsd);
697 _beginthread(xmlGlobalStateCleanupHelper, 0, p);
698 #else
699 EnterCriticalSection(&cleanup_helpers_cs);
700 if (cleanup_helpers_head != NULL) {
701 cleanup_helpers_head->prev = p;
703 p->next = cleanup_helpers_head;
704 p->prev = NULL;
705 cleanup_helpers_head = p;
706 TlsSetValue(globalkey, p);
707 LeaveCriticalSection(&cleanup_helpers_cs);
708 #endif
710 return (tsd);
712 return (globalval);
713 #endif /* HAVE_COMPILER_TLS */
714 #elif defined HAVE_BEOS_THREADS
715 xmlGlobalState *globalval;
717 xmlOnceInit();
719 if ((globalval = (xmlGlobalState *) tls_get(globalkey)) == NULL) {
720 xmlGlobalState *tsd = xmlNewGlobalState();
721 if (tsd == NULL)
722 return (NULL);
724 tls_set(globalkey, tsd);
725 on_exit_thread(xmlGlobalStateCleanup, NULL);
726 return (tsd);
728 return (globalval);
729 #else
730 return (NULL);
731 #endif
734 /************************************************************************
736 * Library wide thread interfaces *
738 ************************************************************************/
741 * xmlGetThreadId:
743 * xmlGetThreadId() find the current thread ID number
744 * Note that this is likely to be broken on some platforms using pthreads
745 * as the specification doesn't mandate pthread_t to be an integer type
747 * Returns the current thread ID number
750 xmlGetThreadId(void)
752 #ifdef HAVE_PTHREAD_H
753 pthread_t id;
754 int ret;
756 if (libxml_is_threaded == 0)
757 return (0);
758 id = pthread_self();
759 /* horrible but preserves compat, see warning above */
760 memcpy(&ret, &id, sizeof(ret));
761 return (ret);
762 #elif defined HAVE_WIN32_THREADS
763 return GetCurrentThreadId();
764 #elif defined HAVE_BEOS_THREADS
765 return find_thread(NULL);
766 #else
767 return ((int) 0);
768 #endif
772 * xmlIsMainThread:
774 * xmlIsMainThread() check whether the current thread is the main thread.
776 * Returns 1 if the current thread is the main thread, 0 otherwise
779 xmlIsMainThread(void)
781 #ifdef HAVE_PTHREAD_H
782 if (libxml_is_threaded == -1)
783 xmlInitThreads();
784 if (libxml_is_threaded == 0)
785 return (1);
786 pthread_once(&once_control, xmlOnceInit);
787 #elif defined HAVE_WIN32_THREADS
788 xmlOnceInit();
789 #elif defined HAVE_BEOS_THREADS
790 xmlOnceInit();
791 #endif
793 #ifdef DEBUG_THREADS
794 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
795 #endif
796 #ifdef HAVE_PTHREAD_H
797 return (pthread_equal(mainthread,pthread_self()));
798 #elif defined HAVE_WIN32_THREADS
799 return (mainthread == GetCurrentThreadId());
800 #elif defined HAVE_BEOS_THREADS
801 return (mainthread == find_thread(NULL));
802 #else
803 return (1);
804 #endif
808 * xmlLockLibrary:
810 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
811 * library.
813 void
814 xmlLockLibrary(void)
816 #ifdef DEBUG_THREADS
817 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
818 #endif
819 xmlRMutexLock(xmlLibraryLock);
823 * xmlUnlockLibrary:
825 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
826 * library.
828 void
829 xmlUnlockLibrary(void)
831 #ifdef DEBUG_THREADS
832 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
833 #endif
834 xmlRMutexUnlock(xmlLibraryLock);
838 * xmlInitThreads:
840 * DEPRECATED: This function will be made private. Call xmlInitParser to
841 * initialize the library.
843 * xmlInitThreads() is used to to initialize all the thread related
844 * data of the libxml2 library.
846 void
847 xmlInitThreads(void)
849 #ifdef HAVE_PTHREAD_H
850 #ifdef XML_PTHREAD_WEAK
851 if (libxml_is_threaded == -1) {
852 if ((pthread_once != NULL) &&
853 (pthread_getspecific != NULL) &&
854 (pthread_setspecific != NULL) &&
855 (pthread_key_create != NULL) &&
856 (pthread_key_delete != NULL) &&
857 (pthread_mutex_init != NULL) &&
858 (pthread_mutex_destroy != NULL) &&
859 (pthread_mutex_lock != NULL) &&
860 (pthread_mutex_unlock != NULL) &&
861 (pthread_cond_init != NULL) &&
862 (pthread_cond_destroy != NULL) &&
863 (pthread_cond_wait != NULL) &&
864 (pthread_equal != NULL) &&
865 (pthread_self != NULL) &&
866 (pthread_cond_signal != NULL)) {
867 libxml_is_threaded = 1;
869 /* fprintf(stderr, "Running multithreaded\n"); */
870 } else {
872 /* fprintf(stderr, "Running without multithread\n"); */
873 libxml_is_threaded = 0;
876 #endif /* XML_PTHREAD_WEAK */
877 #endif
881 * xmlCleanupThreads:
883 * DEPRECATED: This function will be made private. Call xmlCleanupParser
884 * to free global state but see the warnings there. xmlCleanupParser
885 * should be only called once at program exit. In most cases, you don't
886 * have call cleanup functions at all.
888 * xmlCleanupThreads() is used to to cleanup all the thread related
889 * data of the libxml2 library once processing has ended.
891 * WARNING: if your application is multithreaded or has plugin support
892 * calling this may crash the application if another thread or
893 * a plugin is still using libxml2. It's sometimes very hard to
894 * guess if libxml2 is in use in the application, some libraries
895 * or plugins may use it without notice. In case of doubt abstain
896 * from calling this function or do it just before calling exit()
897 * to avoid leak reports from valgrind !
899 void
900 xmlCleanupThreads(void)
902 #ifdef DEBUG_THREADS
903 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
904 #endif
905 #ifdef HAVE_PTHREAD_H
906 if (libxml_is_threaded != 0)
907 pthread_key_delete(globalkey);
908 once_control = once_control_init;
909 #elif defined(HAVE_WIN32_THREADS)
910 #if !defined(HAVE_COMPILER_TLS)
911 if (globalkey != TLS_OUT_OF_INDEXES) {
912 #if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)
913 xmlGlobalStateCleanupHelperParams *p;
915 EnterCriticalSection(&cleanup_helpers_cs);
916 p = cleanup_helpers_head;
917 while (p != NULL) {
918 xmlGlobalStateCleanupHelperParams *temp = p;
920 p = p->next;
921 xmlFreeGlobalState(temp->memory);
922 free(temp);
924 cleanup_helpers_head = 0;
925 LeaveCriticalSection(&cleanup_helpers_cs);
926 #endif
927 TlsFree(globalkey);
928 globalkey = TLS_OUT_OF_INDEXES;
930 #if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)
931 DeleteCriticalSection(&cleanup_helpers_cs);
932 #endif
933 #endif
934 run_once.done = 0;
935 run_once.control = 0;
936 #endif
939 #ifdef LIBXML_THREAD_ENABLED
942 * xmlOnceInit
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
948 * details.
950 static void
951 xmlOnceInit(void)
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 #if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)
962 InitializeCriticalSection(&cleanup_helpers_cs);
963 #endif
964 globalkey = TlsAlloc();
965 #endif
966 mainthread = GetCurrentThreadId();
967 __xmlInitializeDict();
968 run_once.done = 1;
969 } else {
970 /* Another thread is working; give up our slice and
971 * wait until they're done. */
972 while (!run_once.done)
973 Sleep(0);
976 #elif defined HAVE_BEOS_THREADS
977 if (atomic_add(&run_once_init, 1) == 0) {
978 globalkey = tls_allocate();
979 tls_set(globalkey, NULL);
980 mainthread = find_thread(NULL);
981 __xmlInitializeDict();
982 } else
983 atomic_add(&run_once_init, -1);
984 #endif
986 #endif
989 * DllMain:
990 * @hinstDLL: handle to DLL instance
991 * @fdwReason: Reason code for entry
992 * @lpvReserved: generic pointer (depends upon reason code)
994 * Entry point for Windows library. It is being used to free thread-specific
995 * storage.
997 * Returns TRUE always
999 #ifdef HAVE_PTHREAD_H
1000 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
1001 #if defined(LIBXML_STATIC_FOR_DLL)
1002 int XMLCALL
1003 xmlDllMain(ATTRIBUTE_UNUSED void *hinstDLL, unsigned long fdwReason,
1004 ATTRIBUTE_UNUSED void *lpvReserved)
1005 #else
1006 /* declare to avoid "no previous prototype for 'DllMain'" warning */
1007 /* Note that we do NOT want to include this function declaration in
1008 a public header because it's meant to be called by Windows itself,
1009 not a program that uses this library. This also has to be exported. */
1011 XMLPUBFUN BOOL WINAPI
1012 DllMain (HINSTANCE hinstDLL,
1013 DWORD fdwReason,
1014 LPVOID lpvReserved);
1016 BOOL WINAPI
1017 DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL, DWORD fdwReason,
1018 ATTRIBUTE_UNUSED LPVOID lpvReserved)
1019 #endif
1021 switch (fdwReason) {
1022 case DLL_THREAD_DETACH:
1023 if (globalkey != TLS_OUT_OF_INDEXES) {
1024 xmlGlobalState *globalval = NULL;
1025 xmlGlobalStateCleanupHelperParams *p =
1026 (xmlGlobalStateCleanupHelperParams *)
1027 TlsGetValue(globalkey);
1028 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
1029 if (globalval) {
1030 xmlFreeGlobalState(globalval);
1031 TlsSetValue(globalkey, NULL);
1033 if (p) {
1034 EnterCriticalSection(&cleanup_helpers_cs);
1035 if (p == cleanup_helpers_head)
1036 cleanup_helpers_head = p->next;
1037 else
1038 p->prev->next = p->next;
1039 if (p->next != NULL)
1040 p->next->prev = p->prev;
1041 LeaveCriticalSection(&cleanup_helpers_cs);
1042 free(p);
1045 break;
1047 return TRUE;
1049 #endif