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