xref: /reactos/sdk/lib/3rdparty/libxml2/threads.c (revision 911153da)
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