95432d0d04b6344f4522bd1cbeb45dfa243663c2
[reactos.git] / sdk / lib / 3rdparty / libxml2 / threads.c
1 /**
2 * threads.c: set of generic threading related routines
3 *
4 * See Copyright for the status of this software.
5 *
6 * Gary Pennington <Gary.Pennington@uk.sun.com>
7 * daniel@veillard.com
8 */
9
10 #define IN_LIBXML
11 #include "libxml.h"
12
13 #include <string.h>
14
15 #include <libxml/threads.h>
16 #include <libxml/globals.h>
17
18 #ifdef HAVE_SYS_TYPES_H
19 #include <sys/types.h>
20 #endif
21 #ifdef HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
24 #ifdef HAVE_STDLIB_H
25 #include <stdlib.h>
26 #endif
27 #ifdef HAVE_PTHREAD_H
28 #include <pthread.h>
29 #elif defined HAVE_WIN32_THREADS
30 //#define WIN32_LEAN_AND_MEAN
31 //#include <windows.h>
32 #ifndef HAVE_COMPILER_TLS
33 #include <process.h>
34 #endif
35 #endif
36
37 #ifdef HAVE_BEOS_THREADS
38 #include <OS.h>
39 #include <TLS.h>
40 #endif
41
42 #if defined(SOLARIS)
43 #include <note.h>
44 #endif
45
46 /* #define DEBUG_THREADS */
47
48 #ifdef HAVE_PTHREAD_H
49
50 static int libxml_is_threaded = -1;
51 #if defined(__GNUC__) && defined(__GLIBC__)
52 #ifdef __linux__
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
71 #endif
72 #endif /* __linux__ */
73 #endif /* defined(__GNUC__) && defined(__GLIBC__) */
74 #endif /* HAVE_PTHREAD_H */
75
76 /*
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 ...
80 */
81
82 /*
83 * xmlMutex are a simple mutual exception locks
84 */
85 struct _xmlMutex {
86 #ifdef HAVE_PTHREAD_H
87 pthread_mutex_t lock;
88 #elif defined HAVE_WIN32_THREADS
89 HANDLE mutex;
90 #elif defined HAVE_BEOS_THREADS
91 sem_id sem;
92 thread_id tid;
93 #else
94 int empty;
95 #endif
96 };
97
98 /*
99 * xmlRMutex are reentrant mutual exception locks
100 */
101 struct _xmlRMutex {
102 #ifdef HAVE_PTHREAD_H
103 pthread_mutex_t lock;
104 unsigned int held;
105 unsigned int waiters;
106 pthread_t tid;
107 pthread_cond_t cv;
108 #elif defined HAVE_WIN32_THREADS
109 CRITICAL_SECTION cs;
110 unsigned int count;
111 #elif defined HAVE_BEOS_THREADS
112 xmlMutexPtr lock;
113 thread_id tid;
114 int32 count;
115 #else
116 int empty;
117 #endif
118 };
119
120 /*
121 * This module still has some internal static data.
122 * - xmlLibraryLock a global lock
123 * - globalkey used for per-thread data
124 */
125
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;
140 static struct {
141 DWORD done;
142 LONG control;
143 } run_once = { 0, 0};
144 static volatile LPCRITICAL_SECTION global_init_lock = NULL;
145
146 /* endif HAVE_WIN32_THREADS */
147 #elif defined HAVE_BEOS_THREADS
148 int32 globalkey = 0;
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;
153 #endif
154
155 static xmlRMutexPtr xmlLibraryLock = NULL;
156
157 #ifdef LIBXML_THREAD_ENABLED
158 static void xmlOnceInit(void);
159 #endif
160
161 /**
162 * xmlNewMutex:
163 *
164 * xmlNewMutex() is used to allocate a libxml2 token struct for use in
165 * synchronizing access to data.
166 *
167 * Returns a new simple mutex pointer or NULL in case of error
168 */
169 xmlMutexPtr
170 xmlNewMutex(void)
171 {
172 xmlMutexPtr tok;
173
174 if ((tok = malloc(sizeof(xmlMutex))) == NULL)
175 return (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) {
183 free(tok);
184 return NULL;
185 }
186 tok->tid = -1;
187 #endif
188 return (tok);
189 }
190
191 /**
192 * xmlFreeMutex:
193 * @tok: the simple mutex
194 *
195 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
196 * struct.
197 */
198 void
199 xmlFreeMutex(xmlMutexPtr tok)
200 {
201 if (tok == NULL)
202 return;
203
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);
211 #endif
212 free(tok);
213 }
214
215 /**
216 * xmlMutexLock:
217 * @tok: the simple mutex
218 *
219 * xmlMutexLock() is used to lock a libxml2 token.
220 */
221 void
222 xmlMutexLock(xmlMutexPtr tok)
223 {
224 if (tok == NULL)
225 return;
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) {
233 #ifdef DEBUG_THREADS
234 xmlGenericError(xmlGenericErrorContext,
235 "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
236 #endif
237 }
238 tok->tid = find_thread(NULL);
239 #endif
240
241 }
242
243 /**
244 * xmlMutexUnlock:
245 * @tok: the simple mutex
246 *
247 * xmlMutexUnlock() is used to unlock a libxml2 token.
248 */
249 void
250 xmlMutexUnlock(xmlMutexPtr tok)
251 {
252 if (tok == NULL)
253 return;
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)) {
261 tok->tid = -1;
262 release_sem(tok->sem);
263 }
264 #endif
265 }
266
267 /**
268 * xmlNewRMutex:
269 *
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
273 * recursive fashion.
274 *
275 * Returns the new reentrant mutex pointer or NULL in case of error
276 */
277 xmlRMutexPtr
278 xmlNewRMutex(void)
279 {
280 xmlRMutexPtr tok;
281
282 if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
283 return (NULL);
284 #ifdef HAVE_PTHREAD_H
285 if (libxml_is_threaded != 0) {
286 pthread_mutex_init(&tok->lock, NULL);
287 tok->held = 0;
288 tok->waiters = 0;
289 pthread_cond_init(&tok->cv, NULL);
290 }
291 #elif defined HAVE_WIN32_THREADS
292 InitializeCriticalSection(&tok->cs);
293 tok->count = 0;
294 #elif defined HAVE_BEOS_THREADS
295 if ((tok->lock = xmlNewMutex()) == NULL) {
296 free(tok);
297 return NULL;
298 }
299 tok->count = 0;
300 #endif
301 return (tok);
302 }
303
304 /**
305 * xmlFreeRMutex:
306 * @tok: the reentrant mutex
307 *
308 * xmlRFreeMutex() is used to reclaim resources associated with a
309 * reentrant mutex.
310 */
311 void
312 xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
313 {
314 if (tok == NULL)
315 return;
316 #ifdef HAVE_PTHREAD_H
317 if (libxml_is_threaded != 0) {
318 pthread_mutex_destroy(&tok->lock);
319 pthread_cond_destroy(&tok->cv);
320 }
321 #elif defined HAVE_WIN32_THREADS
322 DeleteCriticalSection(&tok->cs);
323 #elif defined HAVE_BEOS_THREADS
324 xmlFreeMutex(tok->lock);
325 #endif
326 free(tok);
327 }
328
329 /**
330 * xmlRMutexLock:
331 * @tok: the reentrant mutex
332 *
333 * xmlRMutexLock() is used to lock a libxml2 token_r.
334 */
335 void
336 xmlRMutexLock(xmlRMutexPtr tok)
337 {
338 if (tok == NULL)
339 return;
340 #ifdef HAVE_PTHREAD_H
341 if (libxml_is_threaded == 0)
342 return;
343
344 pthread_mutex_lock(&tok->lock);
345 if (tok->held) {
346 if (pthread_equal(tok->tid, pthread_self())) {
347 tok->held++;
348 pthread_mutex_unlock(&tok->lock);
349 return;
350 } else {
351 tok->waiters++;
352 while (tok->held)
353 pthread_cond_wait(&tok->cv, &tok->lock);
354 tok->waiters--;
355 }
356 }
357 tok->tid = pthread_self();
358 tok->held = 1;
359 pthread_mutex_unlock(&tok->lock);
360 #elif defined HAVE_WIN32_THREADS
361 EnterCriticalSection(&tok->cs);
362 tok->count++;
363 #elif defined HAVE_BEOS_THREADS
364 if (tok->lock->tid == find_thread(NULL)) {
365 tok->count++;
366 return;
367 } else {
368 xmlMutexLock(tok->lock);
369 tok->count = 1;
370 }
371 #endif
372 }
373
374 /**
375 * xmlRMutexUnlock:
376 * @tok: the reentrant mutex
377 *
378 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
379 */
380 void
381 xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
382 {
383 if (tok == NULL)
384 return;
385 #ifdef HAVE_PTHREAD_H
386 if (libxml_is_threaded == 0)
387 return;
388
389 pthread_mutex_lock(&tok->lock);
390 tok->held--;
391 if (tok->held == 0) {
392 if (tok->waiters)
393 pthread_cond_signal(&tok->cv);
394 memset(&tok->tid, 0, sizeof(tok->tid));
395 }
396 pthread_mutex_unlock(&tok->lock);
397 #elif defined HAVE_WIN32_THREADS
398 if (tok->count > 0) {
399 tok->count--;
400 LeaveCriticalSection(&tok->cs);
401 }
402 #elif defined HAVE_BEOS_THREADS
403 if (tok->lock->tid == find_thread(NULL)) {
404 tok->count--;
405 if (tok->count == 0) {
406 xmlMutexUnlock(tok->lock);
407 }
408 return;
409 }
410 #endif
411 }
412
413 /**
414 * xmlGlobalInitMutexLock
415 *
416 * Makes sure that the global initialization mutex is initialized and
417 * locks it.
418 */
419 void
420 __xmlGlobalInitMutexLock(void)
421 {
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;
429
430 /* Create a new critical section */
431 if (global_init_lock == NULL) {
432 cs = malloc(sizeof(CRITICAL_SECTION));
433 if (cs == NULL) {
434 xmlGenericError(xmlGenericErrorContext,
435 "xmlGlobalInitMutexLock: out of memory\n");
436 return;
437 }
438 InitializeCriticalSection(cs);
439
440 /* Swap it into the global_init_lock */
441 #ifdef InterlockedCompareExchangePointer
442 InterlockedCompareExchangePointer((void **) &global_init_lock,
443 cs, NULL);
444 #else /* Use older void* version */
445 InterlockedCompareExchange((void **) &global_init_lock,
446 (void *) cs, NULL);
447 #endif /* InterlockedCompareExchangePointer */
448
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);
454 free(cs);
455 }
456 }
457
458 /* Lock the chosen critical section */
459 EnterCriticalSection(global_init_lock);
460 #elif defined HAVE_BEOS_THREADS
461 int32 sem;
462
463 /* Allocate a new semaphore */
464 sem = create_sem(1, "xmlGlobalinitMutex");
465
466 while (global_init_lock == -1) {
467 if (atomic_add(&global_init_count, 1) == 0) {
468 global_init_lock = sem;
469 } else {
470 snooze(1);
471 atomic_add(&global_init_count, -1);
472 }
473 }
474
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)
479 delete_sem(sem);
480
481 /* Acquire the chosen semaphore */
482 if (acquire_sem(global_init_lock) != B_NO_ERROR) {
483 #ifdef DEBUG_THREADS
484 xmlGenericError(xmlGenericErrorContext,
485 "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n");
486 #endif
487 }
488 #endif
489 }
490
491 void
492 __xmlGlobalInitMutexUnlock(void)
493 {
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);
500 }
501 #elif defined HAVE_BEOS_THREADS
502 release_sem(global_init_lock);
503 #endif
504 }
505
506 /**
507 * xmlGlobalInitMutexDestroy
508 *
509 * Makes sure that the global initialization mutex is destroyed before
510 * application termination.
511 */
512 void
513 __xmlGlobalInitMutexDestroy(void)
514 {
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;
521 }
522 #endif
523 }
524
525 /************************************************************************
526 * *
527 * Per thread global state handling *
528 * *
529 ************************************************************************/
530
531 #ifdef LIBXML_THREAD_ENABLED
532 #ifdef xmlLastError
533 #undef xmlLastError
534 #endif
535
536 /**
537 * xmlFreeGlobalState:
538 * @state: a thread global state
539 *
540 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
541 * global state. It is is used here to reclaim memory resources.
542 */
543 static void
544 xmlFreeGlobalState(void *state)
545 {
546 xmlGlobalState *gs = (xmlGlobalState *) state;
547
548 /* free any memory allocated in the thread's xmlLastError */
549 xmlResetError(&(gs->xmlLastError));
550 free(state);
551 }
552
553 /**
554 * xmlNewGlobalState:
555 *
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.
559 *
560 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
561 */
562 static xmlGlobalStatePtr
563 xmlNewGlobalState(void)
564 {
565 xmlGlobalState *gs;
566
567 gs = malloc(sizeof(xmlGlobalState));
568 if (gs == NULL) {
569 xmlGenericError(xmlGenericErrorContext,
570 "xmlGetGlobalState: out of memory\n");
571 return (NULL);
572 }
573
574 memset(gs, 0, sizeof(xmlGlobalState));
575 xmlInitializeGlobalState(gs);
576 return (gs);
577 }
578 #endif /* LIBXML_THREAD_ENABLED */
579
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 {
585 HANDLE thread;
586 void *memory;
587 } xmlGlobalStateCleanupHelperParams;
588
589 static void XMLCDECL
590 xmlGlobalStateCleanupHelper(void *p)
591 {
592 xmlGlobalStateCleanupHelperParams *params =
593 (xmlGlobalStateCleanupHelperParams *) p;
594 WaitForSingleObject(params->thread, INFINITE);
595 CloseHandle(params->thread);
596 xmlFreeGlobalState(params->memory);
597 free(params);
598 _endthread();
599 }
600 #else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
601
602 typedef struct _xmlGlobalStateCleanupHelperParams {
603 void *memory;
604 struct _xmlGlobalStateCleanupHelperParams *prev;
605 struct _xmlGlobalStateCleanupHelperParams *next;
606 } xmlGlobalStateCleanupHelperParams;
607
608 static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL;
609 static CRITICAL_SECTION cleanup_helpers_cs;
610
611 #endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
612 #endif /* HAVE_COMPILER_TLS */
613 #endif /* HAVE_WIN32_THREADS */
614
615 #if defined HAVE_BEOS_THREADS
616
617 /**
618 * xmlGlobalStateCleanup:
619 * @data: unused parameter
620 *
621 * Used for Beos only
622 */
623 void
624 xmlGlobalStateCleanup(void *data)
625 {
626 void *globalval = tls_get(globalkey);
627
628 if (globalval != NULL)
629 xmlFreeGlobalState(globalval);
630 }
631 #endif
632
633 /**
634 * xmlGetGlobalState:
635 *
636 * xmlGetGlobalState() is called to retrieve the global state for a thread.
637 *
638 * Returns the thread global state or NULL in case of error
639 */
640 xmlGlobalStatePtr
641 xmlGetGlobalState(void)
642 {
643 #ifdef HAVE_PTHREAD_H
644 xmlGlobalState *globalval;
645
646 if (libxml_is_threaded == 0)
647 return (NULL);
648
649 pthread_once(&once_control, xmlOnceInit);
650
651 if ((globalval = (xmlGlobalState *)
652 pthread_getspecific(globalkey)) == NULL) {
653 xmlGlobalState *tsd = xmlNewGlobalState();
654 if (tsd == NULL)
655 return(NULL);
656
657 pthread_setspecific(globalkey, tsd);
658 return (tsd);
659 }
660 return (globalval);
661 #elif defined HAVE_WIN32_THREADS
662 #if defined(HAVE_COMPILER_TLS)
663 if (!tlstate_inited) {
664 tlstate_inited = 1;
665 xmlInitializeGlobalState(&tlstate);
666 }
667 return &tlstate;
668 #else /* HAVE_COMPILER_TLS */
669 xmlGlobalState *globalval;
670 xmlGlobalStateCleanupHelperParams *p;
671
672 xmlOnceInit();
673 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
674 globalval = (xmlGlobalState *) TlsGetValue(globalkey);
675 #else
676 p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey);
677 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
678 #endif
679 if (globalval == NULL) {
680 xmlGlobalState *tsd = xmlNewGlobalState();
681
682 if (tsd == NULL)
683 return(NULL);
684 p = (xmlGlobalStateCleanupHelperParams *)
685 malloc(sizeof(xmlGlobalStateCleanupHelperParams));
686 if (p == NULL) {
687 xmlGenericError(xmlGenericErrorContext,
688 "xmlGetGlobalState: out of memory\n");
689 xmlFreeGlobalState(tsd);
690 return(NULL);
691 }
692 p->memory = 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);
699 #else
700 EnterCriticalSection(&cleanup_helpers_cs);
701 if (cleanup_helpers_head != NULL) {
702 cleanup_helpers_head->prev = p;
703 }
704 p->next = cleanup_helpers_head;
705 p->prev = NULL;
706 cleanup_helpers_head = p;
707 TlsSetValue(globalkey, p);
708 LeaveCriticalSection(&cleanup_helpers_cs);
709 #endif
710
711 return (tsd);
712 }
713 return (globalval);
714 #endif /* HAVE_COMPILER_TLS */
715 #elif defined HAVE_BEOS_THREADS
716 xmlGlobalState *globalval;
717
718 xmlOnceInit();
719
720 if ((globalval = (xmlGlobalState *) tls_get(globalkey)) == NULL) {
721 xmlGlobalState *tsd = xmlNewGlobalState();
722 if (tsd == NULL)
723 return (NULL);
724
725 tls_set(globalkey, tsd);
726 on_exit_thread(xmlGlobalStateCleanup, NULL);
727 return (tsd);
728 }
729 return (globalval);
730 #else
731 return (NULL);
732 #endif
733 }
734
735 /************************************************************************
736 * *
737 * Library wide thread interfaces *
738 * *
739 ************************************************************************/
740
741 /**
742 * xmlGetThreadId:
743 *
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
747 *
748 * Returns the current thread ID number
749 */
750 int
751 xmlGetThreadId(void)
752 {
753 #ifdef HAVE_PTHREAD_H
754 pthread_t id;
755 int ret;
756
757 if (libxml_is_threaded == 0)
758 return (0);
759 id = pthread_self();
760 /* horrible but preserves compat, see warning above */
761 memcpy(&ret, &id, sizeof(ret));
762 return (ret);
763 #elif defined HAVE_WIN32_THREADS
764 return GetCurrentThreadId();
765 #elif defined HAVE_BEOS_THREADS
766 return find_thread(NULL);
767 #else
768 return ((int) 0);
769 #endif
770 }
771
772 /**
773 * xmlIsMainThread:
774 *
775 * xmlIsMainThread() check whether the current thread is the main thread.
776 *
777 * Returns 1 if the current thread is the main thread, 0 otherwise
778 */
779 int
780 xmlIsMainThread(void)
781 {
782 #ifdef HAVE_PTHREAD_H
783 if (libxml_is_threaded == -1)
784 xmlInitThreads();
785 if (libxml_is_threaded == 0)
786 return (1);
787 pthread_once(&once_control, xmlOnceInit);
788 #elif defined HAVE_WIN32_THREADS
789 xmlOnceInit();
790 #elif defined HAVE_BEOS_THREADS
791 xmlOnceInit();
792 #endif
793
794 #ifdef DEBUG_THREADS
795 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
796 #endif
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));
803 #else
804 return (1);
805 #endif
806 }
807
808 /**
809 * xmlLockLibrary:
810 *
811 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
812 * library.
813 */
814 void
815 xmlLockLibrary(void)
816 {
817 #ifdef DEBUG_THREADS
818 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
819 #endif
820 xmlRMutexLock(xmlLibraryLock);
821 }
822
823 /**
824 * xmlUnlockLibrary:
825 *
826 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
827 * library.
828 */
829 void
830 xmlUnlockLibrary(void)
831 {
832 #ifdef DEBUG_THREADS
833 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
834 #endif
835 xmlRMutexUnlock(xmlLibraryLock);
836 }
837
838 /**
839 * xmlInitThreads:
840 *
841 * xmlInitThreads() is used to to initialize all the thread related
842 * data of the libxml2 library.
843 */
844 void
845 xmlInitThreads(void)
846 {
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;
865
866 /* fprintf(stderr, "Running multithreaded\n"); */
867 } else {
868
869 /* fprintf(stderr, "Running without multithread\n"); */
870 libxml_is_threaded = 0;
871 }
872 }
873 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
874 InitializeCriticalSection(&cleanup_helpers_cs);
875 #endif
876 }
877
878 /**
879 * xmlCleanupThreads:
880 *
881 * xmlCleanupThreads() is used to to cleanup all the thread related
882 * data of the libxml2 library once processing has ended.
883 *
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 !
891 */
892 void
893 xmlCleanupThreads(void)
894 {
895 #ifdef DEBUG_THREADS
896 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
897 #endif
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;
905
906 EnterCriticalSection(&cleanup_helpers_cs);
907 p = cleanup_helpers_head;
908 while (p != NULL) {
909 xmlGlobalStateCleanupHelperParams *temp = p;
910
911 p = p->next;
912 xmlFreeGlobalState(temp->memory);
913 free(temp);
914 }
915 cleanup_helpers_head = 0;
916 LeaveCriticalSection(&cleanup_helpers_cs);
917 TlsFree(globalkey);
918 globalkey = TLS_OUT_OF_INDEXES;
919 }
920 DeleteCriticalSection(&cleanup_helpers_cs);
921 #endif
922 }
923
924 #ifdef LIBXML_THREAD_ENABLED
925
926 /**
927 * xmlOnceInit
928 *
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
933 * details.
934 */
935 static void
936 xmlOnceInit(void)
937 {
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();
947 #endif
948 mainthread = GetCurrentThreadId();
949 __xmlInitializeDict();
950 run_once.done = 1;
951 } else {
952 /* Another thread is working; give up our slice and
953 * wait until they're done. */
954 while (!run_once.done)
955 Sleep(0);
956 }
957 }
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();
964 } else
965 atomic_add(&run_once_init, -1);
966 #endif
967 }
968 #endif
969
970 /**
971 * DllMain:
972 * @hinstDLL: handle to DLL instance
973 * @fdwReason: Reason code for entry
974 * @lpvReserved: generic pointer (depends upon reason code)
975 *
976 * Entry point for Windows library. It is being used to free thread-specific
977 * storage.
978 *
979 * Returns TRUE always
980 */
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)
984 int XMLCALL
985 xmlDllMain(ATTRIBUTE_UNUSED void *hinstDLL, unsigned long fdwReason,
986 ATTRIBUTE_UNUSED void *lpvReserved)
987 #else
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. */
992
993 XMLPUBFUN BOOL WINAPI
994 DllMain (HINSTANCE hinstDLL,
995 DWORD fdwReason,
996 LPVOID lpvReserved);
997
998 BOOL WINAPI
999 DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL, DWORD fdwReason,
1000 ATTRIBUTE_UNUSED LPVOID lpvReserved)
1001 #endif
1002 {
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);
1011 if (globalval) {
1012 xmlFreeGlobalState(globalval);
1013 TlsSetValue(globalkey, NULL);
1014 }
1015 if (p) {
1016 EnterCriticalSection(&cleanup_helpers_cs);
1017 if (p == cleanup_helpers_head)
1018 cleanup_helpers_head = p->next;
1019 else
1020 p->prev->next = p->next;
1021 if (p->next != NULL)
1022 p->next->prev = p->prev;
1023 LeaveCriticalSection(&cleanup_helpers_cs);
1024 free(p);
1025 }
1026 }
1027 break;
1028 }
1029 return TRUE;
1030 }
1031 #endif
1032 #define bottom_threads
1033 #include "elfgcchack.h"