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