Imported Upstream version 2.9.6_rc1
[platform/upstream/libxml2.git] / 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 #include <windows.h>
31 #ifndef HAVE_COMPILER_TLS
32 #include <process.h>
33 #endif
34 #endif
35
36 #ifdef HAVE_BEOS_THREADS
37 #include <OS.h>
38 #include <TLS.h>
39 #endif
40
41 #if defined(SOLARIS)
42 #include <note.h>
43 #endif
44
45 /* #define DEBUG_THREADS */
46
47 #ifdef HAVE_PTHREAD_H
48
49 static int libxml_is_threaded = -1;
50 #if defined(__GNUC__) && defined(__GLIBC__)
51 #ifdef __linux__
52 #if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ > 3)
53 #pragma weak pthread_once
54 #pragma weak pthread_getspecific
55 #pragma weak pthread_setspecific
56 #pragma weak pthread_key_create
57 #pragma weak pthread_key_delete
58 #pragma weak pthread_mutex_init
59 #pragma weak pthread_mutex_destroy
60 #pragma weak pthread_mutex_lock
61 #pragma weak pthread_mutex_unlock
62 #pragma weak pthread_cond_init
63 #pragma weak pthread_cond_destroy
64 #pragma weak pthread_cond_wait
65 #pragma weak pthread_equal
66 #pragma weak pthread_self
67 #pragma weak pthread_key_create
68 #pragma weak pthread_key_delete
69 #pragma weak pthread_cond_signal
70 #endif
71 #endif /* __linux__ */
72 #endif /* defined(__GNUC__) && defined(__GLIBC__) */
73 #endif /* HAVE_PTHREAD_H */
74
75 /*
76  * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree
77  *       to avoid some crazyness since xmlMalloc/xmlFree may actually
78  *       be hosted on allocated blocks needing them for the allocation ...
79  */
80
81 /*
82  * xmlMutex are a simple mutual exception locks
83  */
84 struct _xmlMutex {
85 #ifdef HAVE_PTHREAD_H
86     pthread_mutex_t lock;
87 #elif defined HAVE_WIN32_THREADS
88     HANDLE mutex;
89 #elif defined HAVE_BEOS_THREADS
90     sem_id sem;
91     thread_id tid;
92 #else
93     int empty;
94 #endif
95 };
96
97 /*
98  * xmlRMutex are reentrant mutual exception locks
99  */
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     unsigned int count;
110 #elif defined HAVE_BEOS_THREADS
111     xmlMutexPtr lock;
112     thread_id tid;
113     int32 count;
114 #else
115     int empty;
116 #endif
117 };
118
119 /*
120  * This module still has some internal static data.
121  *   - xmlLibraryLock a global lock
122  *   - globalkey used for per-thread data
123  */
124
125 #ifdef HAVE_PTHREAD_H
126 static pthread_key_t globalkey;
127 static pthread_t mainthread;
128 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
129 static pthread_once_t once_control_init = PTHREAD_ONCE_INIT;
130 static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
131 #elif defined HAVE_WIN32_THREADS
132 #if defined(HAVE_COMPILER_TLS)
133 static __declspec(thread) xmlGlobalState tlstate;
134 static __declspec(thread) int tlstate_inited = 0;
135 #else /* HAVE_COMPILER_TLS */
136 static DWORD globalkey = TLS_OUT_OF_INDEXES;
137 #endif /* HAVE_COMPILER_TLS */
138 static DWORD mainthread;
139 static struct {
140     DWORD done;
141     DWORD control;
142 } run_once = { 0, 0};
143 static volatile LPCRITICAL_SECTION global_init_lock = NULL;
144
145 /* endif HAVE_WIN32_THREADS */
146 #elif defined HAVE_BEOS_THREADS
147 int32 globalkey = 0;
148 thread_id mainthread = 0;
149 int32 run_once_init = 0;
150 static int32 global_init_lock = -1;
151 static vint32 global_init_count = 0;
152 #endif
153
154 static xmlRMutexPtr xmlLibraryLock = NULL;
155
156 #ifdef LIBXML_THREAD_ENABLED
157 static void xmlOnceInit(void);
158 #endif
159
160 /**
161  * xmlNewMutex:
162  *
163  * xmlNewMutex() is used to allocate a libxml2 token struct for use in
164  * synchronizing access to data.
165  *
166  * Returns a new simple mutex pointer or NULL in case of error
167  */
168 xmlMutexPtr
169 xmlNewMutex(void)
170 {
171     xmlMutexPtr tok;
172
173     if ((tok = malloc(sizeof(xmlMutex))) == NULL)
174         return (NULL);
175 #ifdef HAVE_PTHREAD_H
176     if (libxml_is_threaded != 0)
177         pthread_mutex_init(&tok->lock, NULL);
178 #elif defined HAVE_WIN32_THREADS
179     tok->mutex = CreateMutex(NULL, FALSE, NULL);
180 #elif defined HAVE_BEOS_THREADS
181     if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) {
182         free(tok);
183         return NULL;
184     }
185     tok->tid = -1;
186 #endif
187     return (tok);
188 }
189
190 /**
191  * xmlFreeMutex:
192  * @tok:  the simple mutex
193  *
194  * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
195  * struct.
196  */
197 void
198 xmlFreeMutex(xmlMutexPtr tok)
199 {
200     if (tok == NULL)
201         return;
202
203 #ifdef HAVE_PTHREAD_H
204     if (libxml_is_threaded != 0)
205         pthread_mutex_destroy(&tok->lock);
206 #elif defined HAVE_WIN32_THREADS
207     CloseHandle(tok->mutex);
208 #elif defined HAVE_BEOS_THREADS
209     delete_sem(tok->sem);
210 #endif
211     free(tok);
212 }
213
214 /**
215  * xmlMutexLock:
216  * @tok:  the simple mutex
217  *
218  * xmlMutexLock() is used to lock a libxml2 token.
219  */
220 void
221 xmlMutexLock(xmlMutexPtr tok)
222 {
223     if (tok == NULL)
224         return;
225 #ifdef HAVE_PTHREAD_H
226     if (libxml_is_threaded != 0)
227         pthread_mutex_lock(&tok->lock);
228 #elif defined HAVE_WIN32_THREADS
229     WaitForSingleObject(tok->mutex, INFINITE);
230 #elif defined HAVE_BEOS_THREADS
231     if (acquire_sem(tok->sem) != B_NO_ERROR) {
232 #ifdef DEBUG_THREADS
233         xmlGenericError(xmlGenericErrorContext,
234                         "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
235 #endif
236     }
237     tok->tid = find_thread(NULL);
238 #endif
239
240 }
241
242 /**
243  * xmlMutexUnlock:
244  * @tok:  the simple mutex
245  *
246  * xmlMutexUnlock() is used to unlock a libxml2 token.
247  */
248 void
249 xmlMutexUnlock(xmlMutexPtr tok)
250 {
251     if (tok == NULL)
252         return;
253 #ifdef HAVE_PTHREAD_H
254     if (libxml_is_threaded != 0)
255         pthread_mutex_unlock(&tok->lock);
256 #elif defined HAVE_WIN32_THREADS
257     ReleaseMutex(tok->mutex);
258 #elif defined HAVE_BEOS_THREADS
259     if (tok->tid == find_thread(NULL)) {
260         tok->tid = -1;
261         release_sem(tok->sem);
262     }
263 #endif
264 }
265
266 /**
267  * xmlNewRMutex:
268  *
269  * xmlRNewMutex() is used to allocate a reentrant mutex for use in
270  * synchronizing access to data. token_r is a re-entrant lock and thus useful
271  * for synchronizing access to data structures that may be manipulated in a
272  * recursive fashion.
273  *
274  * Returns the new reentrant mutex pointer or NULL in case of error
275  */
276 xmlRMutexPtr
277 xmlNewRMutex(void)
278 {
279     xmlRMutexPtr tok;
280
281     if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
282         return (NULL);
283 #ifdef HAVE_PTHREAD_H
284     if (libxml_is_threaded != 0) {
285         pthread_mutex_init(&tok->lock, NULL);
286         tok->held = 0;
287         tok->waiters = 0;
288         pthread_cond_init(&tok->cv, NULL);
289     }
290 #elif defined HAVE_WIN32_THREADS
291     InitializeCriticalSection(&tok->cs);
292     tok->count = 0;
293 #elif defined HAVE_BEOS_THREADS
294     if ((tok->lock = xmlNewMutex()) == NULL) {
295         free(tok);
296         return NULL;
297     }
298     tok->count = 0;
299 #endif
300     return (tok);
301 }
302
303 /**
304  * xmlFreeRMutex:
305  * @tok:  the reentrant mutex
306  *
307  * xmlRFreeMutex() is used to reclaim resources associated with a
308  * reentrant mutex.
309  */
310 void
311 xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
312 {
313     if (tok == NULL)
314         return;
315 #ifdef HAVE_PTHREAD_H
316     if (libxml_is_threaded != 0) {
317         pthread_mutex_destroy(&tok->lock);
318         pthread_cond_destroy(&tok->cv);
319     }
320 #elif defined HAVE_WIN32_THREADS
321     DeleteCriticalSection(&tok->cs);
322 #elif defined HAVE_BEOS_THREADS
323     xmlFreeMutex(tok->lock);
324 #endif
325     free(tok);
326 }
327
328 /**
329  * xmlRMutexLock:
330  * @tok:  the reentrant mutex
331  *
332  * xmlRMutexLock() is used to lock a libxml2 token_r.
333  */
334 void
335 xmlRMutexLock(xmlRMutexPtr tok)
336 {
337     if (tok == NULL)
338         return;
339 #ifdef HAVE_PTHREAD_H
340     if (libxml_is_threaded == 0)
341         return;
342
343     pthread_mutex_lock(&tok->lock);
344     if (tok->held) {
345         if (pthread_equal(tok->tid, pthread_self())) {
346             tok->held++;
347             pthread_mutex_unlock(&tok->lock);
348             return;
349         } else {
350             tok->waiters++;
351             while (tok->held)
352                 pthread_cond_wait(&tok->cv, &tok->lock);
353             tok->waiters--;
354         }
355     }
356     tok->tid = pthread_self();
357     tok->held = 1;
358     pthread_mutex_unlock(&tok->lock);
359 #elif defined HAVE_WIN32_THREADS
360     EnterCriticalSection(&tok->cs);
361     tok->count++;
362 #elif defined HAVE_BEOS_THREADS
363     if (tok->lock->tid == find_thread(NULL)) {
364         tok->count++;
365         return;
366     } else {
367         xmlMutexLock(tok->lock);
368         tok->count = 1;
369     }
370 #endif
371 }
372
373 /**
374  * xmlRMutexUnlock:
375  * @tok:  the reentrant mutex
376  *
377  * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
378  */
379 void
380 xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
381 {
382     if (tok == NULL)
383         return;
384 #ifdef HAVE_PTHREAD_H
385     if (libxml_is_threaded == 0)
386         return;
387
388     pthread_mutex_lock(&tok->lock);
389     tok->held--;
390     if (tok->held == 0) {
391         if (tok->waiters)
392             pthread_cond_signal(&tok->cv);
393         memset(&tok->tid, 0, sizeof(tok->tid));
394     }
395     pthread_mutex_unlock(&tok->lock);
396 #elif defined HAVE_WIN32_THREADS
397     if (tok->count > 0) {
398         tok->count--;
399         LeaveCriticalSection(&tok->cs);
400     }
401 #elif defined HAVE_BEOS_THREADS
402     if (tok->lock->tid == find_thread(NULL)) {
403         tok->count--;
404         if (tok->count == 0) {
405             xmlMutexUnlock(tok->lock);
406         }
407         return;
408     }
409 #endif
410 }
411
412 /**
413  * xmlGlobalInitMutexLock
414  *
415  * Makes sure that the global initialization mutex is initialized and
416  * locks it.
417  */
418 void
419 __xmlGlobalInitMutexLock(void)
420 {
421     /* Make sure the global init lock is initialized and then lock it. */
422 #ifdef HAVE_PTHREAD_H
423     /* The mutex is statically initialized, so we just lock it. */
424     if (pthread_mutex_lock != NULL)
425         pthread_mutex_lock(&global_init_lock);
426 #elif defined HAVE_WIN32_THREADS
427     LPCRITICAL_SECTION cs;
428
429     /* Create a new critical section */
430     if (global_init_lock == NULL) {
431         cs = malloc(sizeof(CRITICAL_SECTION));
432         if (cs == NULL) {
433             xmlGenericError(xmlGenericErrorContext,
434                             "xmlGlobalInitMutexLock: out of memory\n");
435             return;
436         }
437         InitializeCriticalSection(cs);
438
439         /* Swap it into the global_init_lock */
440 #ifdef InterlockedCompareExchangePointer
441         InterlockedCompareExchangePointer(&global_init_lock, cs, NULL);
442 #else /* Use older void* version */
443         InterlockedCompareExchange((void **) &global_init_lock,
444                                    (void *) cs, NULL);
445 #endif /* InterlockedCompareExchangePointer */
446
447         /* If another thread successfully recorded its critical
448          * section in the global_init_lock then discard the one
449          * allocated by this thread. */
450         if (global_init_lock != cs) {
451             DeleteCriticalSection(cs);
452             free(cs);
453         }
454     }
455
456     /* Lock the chosen critical section */
457     EnterCriticalSection(global_init_lock);
458 #elif defined HAVE_BEOS_THREADS
459     int32 sem;
460
461     /* Allocate a new semaphore */
462     sem = create_sem(1, "xmlGlobalinitMutex");
463
464     while (global_init_lock == -1) {
465         if (atomic_add(&global_init_count, 1) == 0) {
466             global_init_lock = sem;
467         } else {
468             snooze(1);
469             atomic_add(&global_init_count, -1);
470         }
471     }
472
473     /* If another thread successfully recorded its critical
474      * section in the global_init_lock then discard the one
475      * allocated by this thread. */
476     if (global_init_lock != sem)
477         delete_sem(sem);
478
479     /* Acquire the chosen semaphore */
480     if (acquire_sem(global_init_lock) != B_NO_ERROR) {
481 #ifdef DEBUG_THREADS
482         xmlGenericError(xmlGenericErrorContext,
483                         "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n");
484 #endif
485     }
486 #endif
487 }
488
489 void
490 __xmlGlobalInitMutexUnlock(void)
491 {
492 #ifdef HAVE_PTHREAD_H
493     if (pthread_mutex_unlock != NULL)
494         pthread_mutex_unlock(&global_init_lock);
495 #elif defined HAVE_WIN32_THREADS
496     if (global_init_lock != NULL) {
497         LeaveCriticalSection(global_init_lock);
498     }
499 #elif defined HAVE_BEOS_THREADS
500     release_sem(global_init_lock);
501 #endif
502 }
503
504 /**
505  * xmlGlobalInitMutexDestroy
506  *
507  * Makes sure that the global initialization mutex is destroyed before
508  * application termination.
509  */
510 void
511 __xmlGlobalInitMutexDestroy(void)
512 {
513 #ifdef HAVE_PTHREAD_H
514 #elif defined HAVE_WIN32_THREADS
515     if (global_init_lock != NULL) {
516         DeleteCriticalSection(global_init_lock);
517         free(global_init_lock);
518         global_init_lock = NULL;
519     }
520 #endif
521 }
522
523 /************************************************************************
524  *                                                                      *
525  *                      Per thread global state handling                *
526  *                                                                      *
527  ************************************************************************/
528
529 #ifdef LIBXML_THREAD_ENABLED
530 #ifdef xmlLastError
531 #undef xmlLastError
532 #endif
533
534 /**
535  * xmlFreeGlobalState:
536  * @state:  a thread global state
537  *
538  * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
539  * global state. It is is used here to reclaim memory resources.
540  */
541 static void
542 xmlFreeGlobalState(void *state)
543 {
544     xmlGlobalState *gs = (xmlGlobalState *) state;
545
546     /* free any memory allocated in the thread's xmlLastError */
547     xmlResetError(&(gs->xmlLastError));
548     free(state);
549 }
550
551 /**
552  * xmlNewGlobalState:
553  *
554  * xmlNewGlobalState() allocates a global state. This structure is used to
555  * hold all data for use by a thread when supporting backwards compatibility
556  * of libxml2 to pre-thread-safe behaviour.
557  *
558  * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
559  */
560 static xmlGlobalStatePtr
561 xmlNewGlobalState(void)
562 {
563     xmlGlobalState *gs;
564
565     gs = malloc(sizeof(xmlGlobalState));
566     if (gs == NULL) {
567         xmlGenericError(xmlGenericErrorContext,
568                         "xmlGetGlobalState: out of memory\n");
569         return (NULL);
570     }
571
572     memset(gs, 0, sizeof(xmlGlobalState));
573     xmlInitializeGlobalState(gs);
574     return (gs);
575 }
576 #endif /* LIBXML_THREAD_ENABLED */
577
578 #ifdef HAVE_PTHREAD_H
579 #elif defined HAVE_WIN32_THREADS
580 #if !defined(HAVE_COMPILER_TLS)
581 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
582 typedef struct _xmlGlobalStateCleanupHelperParams {
583     HANDLE thread;
584     void *memory;
585 } xmlGlobalStateCleanupHelperParams;
586
587 static void XMLCDECL
588 xmlGlobalStateCleanupHelper(void *p)
589 {
590     xmlGlobalStateCleanupHelperParams *params =
591         (xmlGlobalStateCleanupHelperParams *) p;
592     WaitForSingleObject(params->thread, INFINITE);
593     CloseHandle(params->thread);
594     xmlFreeGlobalState(params->memory);
595     free(params);
596     _endthread();
597 }
598 #else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
599
600 typedef struct _xmlGlobalStateCleanupHelperParams {
601     void *memory;
602     struct _xmlGlobalStateCleanupHelperParams *prev;
603     struct _xmlGlobalStateCleanupHelperParams *next;
604 } xmlGlobalStateCleanupHelperParams;
605
606 static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL;
607 static CRITICAL_SECTION cleanup_helpers_cs;
608
609 #endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
610 #endif /* HAVE_COMPILER_TLS */
611 #endif /* HAVE_WIN32_THREADS */
612
613 #if defined HAVE_BEOS_THREADS
614
615 /**
616  * xmlGlobalStateCleanup:
617  * @data: unused parameter
618  *
619  * Used for Beos only
620  */
621 void
622 xmlGlobalStateCleanup(void *data)
623 {
624     void *globalval = tls_get(globalkey);
625
626     if (globalval != NULL)
627         xmlFreeGlobalState(globalval);
628 }
629 #endif
630
631 /**
632  * xmlGetGlobalState:
633  *
634  * xmlGetGlobalState() is called to retrieve the global state for a thread.
635  *
636  * Returns the thread global state or NULL in case of error
637  */
638 xmlGlobalStatePtr
639 xmlGetGlobalState(void)
640 {
641 #ifdef HAVE_PTHREAD_H
642     xmlGlobalState *globalval;
643
644     if (libxml_is_threaded == 0)
645         return (NULL);
646
647     pthread_once(&once_control, xmlOnceInit);
648
649     if ((globalval = (xmlGlobalState *)
650          pthread_getspecific(globalkey)) == NULL) {
651         xmlGlobalState *tsd = xmlNewGlobalState();
652         if (tsd == NULL)
653             return(NULL);
654
655         pthread_setspecific(globalkey, tsd);
656         return (tsd);
657     }
658     return (globalval);
659 #elif defined HAVE_WIN32_THREADS
660 #if defined(HAVE_COMPILER_TLS)
661     if (!tlstate_inited) {
662         tlstate_inited = 1;
663         xmlInitializeGlobalState(&tlstate);
664     }
665     return &tlstate;
666 #else /* HAVE_COMPILER_TLS */
667     xmlGlobalState *globalval;
668     xmlGlobalStateCleanupHelperParams *p;
669
670     xmlOnceInit();
671 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
672     globalval = (xmlGlobalState *) TlsGetValue(globalkey);
673 #else
674     p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey);
675     globalval = (xmlGlobalState *) (p ? p->memory : NULL);
676 #endif
677     if (globalval == NULL) {
678         xmlGlobalState *tsd = xmlNewGlobalState();
679
680         if (tsd == NULL)
681             return(NULL);
682         p = (xmlGlobalStateCleanupHelperParams *)
683             malloc(sizeof(xmlGlobalStateCleanupHelperParams));
684         if (p == NULL) {
685             xmlGenericError(xmlGenericErrorContext,
686                             "xmlGetGlobalState: out of memory\n");
687             xmlFreeGlobalState(tsd);
688             return(NULL);
689         }
690         p->memory = tsd;
691 #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
692         DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
693                         GetCurrentProcess(), &p->thread, 0, TRUE,
694                         DUPLICATE_SAME_ACCESS);
695         TlsSetValue(globalkey, tsd);
696         _beginthread(xmlGlobalStateCleanupHelper, 0, p);
697 #else
698         EnterCriticalSection(&cleanup_helpers_cs);
699         if (cleanup_helpers_head != NULL) {
700             cleanup_helpers_head->prev = p;
701         }
702         p->next = cleanup_helpers_head;
703         p->prev = NULL;
704         cleanup_helpers_head = p;
705         TlsSetValue(globalkey, p);
706         LeaveCriticalSection(&cleanup_helpers_cs);
707 #endif
708
709         return (tsd);
710     }
711     return (globalval);
712 #endif /* HAVE_COMPILER_TLS */
713 #elif defined HAVE_BEOS_THREADS
714     xmlGlobalState *globalval;
715
716     xmlOnceInit();
717
718     if ((globalval = (xmlGlobalState *) tls_get(globalkey)) == NULL) {
719         xmlGlobalState *tsd = xmlNewGlobalState();
720         if (tsd == NULL)
721             return (NULL);
722
723         tls_set(globalkey, tsd);
724         on_exit_thread(xmlGlobalStateCleanup, NULL);
725         return (tsd);
726     }
727     return (globalval);
728 #else
729     return (NULL);
730 #endif
731 }
732
733 /************************************************************************
734  *                                                                      *
735  *                      Library wide thread interfaces                  *
736  *                                                                      *
737  ************************************************************************/
738
739 /**
740  * xmlGetThreadId:
741  *
742  * xmlGetThreadId() find the current thread ID number
743  * Note that this is likely to be broken on some platforms using pthreads
744  * as the specification doesn't mandate pthread_t to be an integer type
745  *
746  * Returns the current thread ID number
747  */
748 int
749 xmlGetThreadId(void)
750 {
751 #ifdef HAVE_PTHREAD_H
752     pthread_t id;
753     int ret;
754
755     if (libxml_is_threaded == 0)
756         return (0);
757     id = pthread_self();
758     /* horrible but preserves compat, see warning above */
759     memcpy(&ret, &id, sizeof(ret));
760     return (ret);
761 #elif defined HAVE_WIN32_THREADS
762     return GetCurrentThreadId();
763 #elif defined HAVE_BEOS_THREADS
764     return find_thread(NULL);
765 #else
766     return ((int) 0);
767 #endif
768 }
769
770 /**
771  * xmlIsMainThread:
772  *
773  * xmlIsMainThread() check whether the current thread is the main thread.
774  *
775  * Returns 1 if the current thread is the main thread, 0 otherwise
776  */
777 int
778 xmlIsMainThread(void)
779 {
780 #ifdef HAVE_PTHREAD_H
781     if (libxml_is_threaded == -1)
782         xmlInitThreads();
783     if (libxml_is_threaded == 0)
784         return (1);
785     pthread_once(&once_control, xmlOnceInit);
786 #elif defined HAVE_WIN32_THREADS
787     xmlOnceInit();
788 #elif defined HAVE_BEOS_THREADS
789     xmlOnceInit();
790 #endif
791
792 #ifdef DEBUG_THREADS
793     xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
794 #endif
795 #ifdef HAVE_PTHREAD_H
796     return (pthread_equal(mainthread,pthread_self()));
797 #elif defined HAVE_WIN32_THREADS
798     return (mainthread == GetCurrentThreadId());
799 #elif defined HAVE_BEOS_THREADS
800     return (mainthread == find_thread(NULL));
801 #else
802     return (1);
803 #endif
804 }
805
806 /**
807  * xmlLockLibrary:
808  *
809  * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
810  * library.
811  */
812 void
813 xmlLockLibrary(void)
814 {
815 #ifdef DEBUG_THREADS
816     xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
817 #endif
818     xmlRMutexLock(xmlLibraryLock);
819 }
820
821 /**
822  * xmlUnlockLibrary:
823  *
824  * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
825  * library.
826  */
827 void
828 xmlUnlockLibrary(void)
829 {
830 #ifdef DEBUG_THREADS
831     xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
832 #endif
833     xmlRMutexUnlock(xmlLibraryLock);
834 }
835
836 /**
837  * xmlInitThreads:
838  *
839  * xmlInitThreads() is used to to initialize all the thread related
840  * data of the libxml2 library.
841  */
842 void
843 xmlInitThreads(void)
844 {
845 #ifdef HAVE_PTHREAD_H
846     if (libxml_is_threaded == -1) {
847         if ((pthread_once != NULL) &&
848             (pthread_getspecific != NULL) &&
849             (pthread_setspecific != NULL) &&
850             (pthread_key_create != NULL) &&
851             (pthread_key_delete != NULL) &&
852             (pthread_mutex_init != NULL) &&
853             (pthread_mutex_destroy != NULL) &&
854             (pthread_mutex_lock != NULL) &&
855             (pthread_mutex_unlock != NULL) &&
856             (pthread_cond_init != NULL) &&
857             (pthread_cond_destroy != NULL) &&
858             (pthread_cond_wait != NULL) &&
859             (pthread_equal != NULL) &&
860             (pthread_self != NULL) &&
861             (pthread_cond_signal != NULL)) {
862             libxml_is_threaded = 1;
863
864 /* fprintf(stderr, "Running multithreaded\n"); */
865         } else {
866
867 /* fprintf(stderr, "Running without multithread\n"); */
868             libxml_is_threaded = 0;
869         }
870     }
871 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
872     InitializeCriticalSection(&cleanup_helpers_cs);
873 #endif
874 }
875
876 /**
877  * xmlCleanupThreads:
878  *
879  * xmlCleanupThreads() is used to to cleanup all the thread related
880  * data of the libxml2 library once processing has ended.
881  *
882  * WARNING: if your application is multithreaded or has plugin support
883  *          calling this may crash the application if another thread or
884  *          a plugin is still using libxml2. It's sometimes very hard to
885  *          guess if libxml2 is in use in the application, some libraries
886  *          or plugins may use it without notice. In case of doubt abstain
887  *          from calling this function or do it just before calling exit()
888  *          to avoid leak reports from valgrind !
889  */
890 void
891 xmlCleanupThreads(void)
892 {
893 #ifdef DEBUG_THREADS
894     xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
895 #endif
896 #ifdef HAVE_PTHREAD_H
897     if ((libxml_is_threaded)  && (pthread_key_delete != NULL))
898         pthread_key_delete(globalkey);
899     once_control = once_control_init;
900 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
901     if (globalkey != TLS_OUT_OF_INDEXES) {
902         xmlGlobalStateCleanupHelperParams *p;
903
904         EnterCriticalSection(&cleanup_helpers_cs);
905         p = cleanup_helpers_head;
906         while (p != NULL) {
907             xmlGlobalStateCleanupHelperParams *temp = p;
908
909             p = p->next;
910             xmlFreeGlobalState(temp->memory);
911             free(temp);
912         }
913         cleanup_helpers_head = 0;
914         LeaveCriticalSection(&cleanup_helpers_cs);
915         TlsFree(globalkey);
916         globalkey = TLS_OUT_OF_INDEXES;
917     }
918     DeleteCriticalSection(&cleanup_helpers_cs);
919 #endif
920 }
921
922 #ifdef LIBXML_THREAD_ENABLED
923
924 /**
925  * xmlOnceInit
926  *
927  * xmlOnceInit() is used to initialize the value of mainthread for use
928  * in other routines. This function should only be called using
929  * pthread_once() in association with the once_control variable to ensure
930  * that the function is only called once. See man pthread_once for more
931  * details.
932  */
933 static void
934 xmlOnceInit(void)
935 {
936 #ifdef HAVE_PTHREAD_H
937     (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
938     mainthread = pthread_self();
939     __xmlInitializeDict();
940 #elif defined(HAVE_WIN32_THREADS)
941     if (!run_once.done) {
942         if (InterlockedIncrement(&run_once.control) == 1) {
943 #if !defined(HAVE_COMPILER_TLS)
944             globalkey = TlsAlloc();
945 #endif
946             mainthread = GetCurrentThreadId();
947             __xmlInitializeDict();
948             run_once.done = 1;
949         } else {
950             /* Another thread is working; give up our slice and
951              * wait until they're done. */
952             while (!run_once.done)
953                 Sleep(0);
954         }
955     }
956 #elif defined HAVE_BEOS_THREADS
957     if (atomic_add(&run_once_init, 1) == 0) {
958         globalkey = tls_allocate();
959         tls_set(globalkey, NULL);
960         mainthread = find_thread(NULL);
961         __xmlInitializeDict();
962     } else
963         atomic_add(&run_once_init, -1);
964 #endif
965 }
966 #endif
967
968 /**
969  * DllMain:
970  * @hinstDLL: handle to DLL instance
971  * @fdwReason: Reason code for entry
972  * @lpvReserved: generic pointer (depends upon reason code)
973  *
974  * Entry point for Windows library. It is being used to free thread-specific
975  * storage.
976  *
977  * Returns TRUE always
978  */
979 #ifdef HAVE_PTHREAD_H
980 #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
981 #if defined(LIBXML_STATIC_FOR_DLL)
982 BOOL XMLCALL
983 xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
984 #else
985 BOOL WINAPI
986 DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
987 #endif
988 {
989     switch (fdwReason) {
990         case DLL_THREAD_DETACH:
991             if (globalkey != TLS_OUT_OF_INDEXES) {
992                 xmlGlobalState *globalval = NULL;
993                 xmlGlobalStateCleanupHelperParams *p =
994                     (xmlGlobalStateCleanupHelperParams *)
995                     TlsGetValue(globalkey);
996                 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
997                 if (globalval) {
998                     xmlFreeGlobalState(globalval);
999                     TlsSetValue(globalkey, NULL);
1000                 }
1001                 if (p) {
1002                     EnterCriticalSection(&cleanup_helpers_cs);
1003                     if (p == cleanup_helpers_head)
1004                         cleanup_helpers_head = p->next;
1005                     else
1006                         p->prev->next = p->next;
1007                     if (p->next != NULL)
1008                         p->next->prev = p->prev;
1009                     LeaveCriticalSection(&cleanup_helpers_cs);
1010                     free(p);
1011                 }
1012             }
1013             break;
1014     }
1015     return TRUE;
1016 }
1017 #endif
1018 #define bottom_threads
1019 #include "elfgcchack.h"