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