1 | /**
|
---|
2 | * threads.c: set of generic threading related routines
|
---|
3 | *
|
---|
4 | * See Copyright for the status of this software.
|
---|
5 | *
|
---|
6 | * Gary Pennington <[email protected]>
|
---|
7 | * [email protected]
|
---|
8 | */
|
---|
9 |
|
---|
10 | #define IN_LIBXML
|
---|
11 | #include "libxml.h"
|
---|
12 |
|
---|
13 | #include <string.h>
|
---|
14 | #include <stdlib.h>
|
---|
15 |
|
---|
16 | #include <libxml/threads.h>
|
---|
17 | #include <libxml/parser.h>
|
---|
18 | #ifdef LIBXML_CATALOG_ENABLED
|
---|
19 | #include <libxml/catalog.h>
|
---|
20 | #endif
|
---|
21 | #ifdef LIBXML_SCHEMAS_ENABLED
|
---|
22 | #include <libxml/xmlschemastypes.h>
|
---|
23 | #include <libxml/relaxng.h>
|
---|
24 | #endif
|
---|
25 |
|
---|
26 | #if defined(SOLARIS)
|
---|
27 | #include <note.h>
|
---|
28 | #endif
|
---|
29 |
|
---|
30 | #include "private/dict.h"
|
---|
31 | #include "private/enc.h"
|
---|
32 | #include "private/globals.h"
|
---|
33 | #include "private/io.h"
|
---|
34 | #include "private/memory.h"
|
---|
35 | #include "private/threads.h"
|
---|
36 | #include "private/xpath.h"
|
---|
37 |
|
---|
38 | #if defined(HAVE_POSIX_THREADS) && \
|
---|
39 | defined(__GLIBC__) && \
|
---|
40 | __GLIBC__ * 100 + __GLIBC_MINOR__ >= 234
|
---|
41 |
|
---|
42 | /*
|
---|
43 | * The modern way available since glibc 2.32.
|
---|
44 | *
|
---|
45 | * The check above is for glibc 2.34 which merged the pthread symbols into
|
---|
46 | * libc. Since we still allow linking without pthread symbols (see below),
|
---|
47 | * this only works if pthread symbols are guaranteed to be available.
|
---|
48 | */
|
---|
49 |
|
---|
50 | #include <sys/single_threaded.h>
|
---|
51 |
|
---|
52 | #define XML_IS_THREADED() (!__libc_single_threaded)
|
---|
53 | #define XML_IS_NEVER_THREADED() 0
|
---|
54 |
|
---|
55 | #elif defined(HAVE_POSIX_THREADS) && \
|
---|
56 | defined(__GLIBC__) && \
|
---|
57 | defined(__GNUC__)
|
---|
58 |
|
---|
59 | /*
|
---|
60 | * The traditional way to check for single-threaded applications with
|
---|
61 | * glibc was to check whether the separate libpthread library is
|
---|
62 | * linked in. This works by not linking libxml2 with libpthread (see
|
---|
63 | * BASE_THREAD_LIBS in configure.ac and Makefile.am) and declaring
|
---|
64 | * pthread functions as weak symbols.
|
---|
65 | *
|
---|
66 | * In glibc 2.34, the pthread symbols were moved from libpthread to libc,
|
---|
67 | * so this doesn't work anymore.
|
---|
68 | *
|
---|
69 | * At some point, this legacy code and the BASE_THREAD_LIBS hack in
|
---|
70 | * configure.ac can probably be removed.
|
---|
71 | */
|
---|
72 |
|
---|
73 | #pragma weak pthread_mutex_init
|
---|
74 | #pragma weak pthread_mutex_destroy
|
---|
75 | #pragma weak pthread_mutex_lock
|
---|
76 | #pragma weak pthread_mutex_unlock
|
---|
77 | #pragma weak pthread_cond_init
|
---|
78 | #pragma weak pthread_cond_destroy
|
---|
79 | #pragma weak pthread_cond_wait
|
---|
80 | #pragma weak pthread_equal
|
---|
81 | #pragma weak pthread_self
|
---|
82 | #pragma weak pthread_cond_signal
|
---|
83 |
|
---|
84 | #define XML_PTHREAD_WEAK
|
---|
85 | #define XML_IS_THREADED() libxml_is_threaded
|
---|
86 | #define XML_IS_NEVER_THREADED() (!libxml_is_threaded)
|
---|
87 |
|
---|
88 | static int libxml_is_threaded = -1;
|
---|
89 |
|
---|
90 | #else /* other POSIX platforms */
|
---|
91 |
|
---|
92 | #define XML_IS_THREADED() 1
|
---|
93 | #define XML_IS_NEVER_THREADED() 0
|
---|
94 |
|
---|
95 | #endif
|
---|
96 |
|
---|
97 | /*
|
---|
98 | * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree
|
---|
99 | * to avoid some craziness since xmlMalloc/xmlFree may actually
|
---|
100 | * be hosted on allocated blocks needing them for the allocation ...
|
---|
101 | */
|
---|
102 |
|
---|
103 | /*
|
---|
104 | * xmlRMutex are reentrant mutual exception locks
|
---|
105 | */
|
---|
106 | struct _xmlRMutex {
|
---|
107 | #ifdef HAVE_POSIX_THREADS
|
---|
108 | pthread_mutex_t lock;
|
---|
109 | unsigned int held;
|
---|
110 | unsigned int waiters;
|
---|
111 | pthread_t tid;
|
---|
112 | pthread_cond_t cv;
|
---|
113 | #elif defined HAVE_WIN32_THREADS
|
---|
114 | CRITICAL_SECTION cs;
|
---|
115 | #else
|
---|
116 | int empty;
|
---|
117 | #endif
|
---|
118 | };
|
---|
119 |
|
---|
120 | static xmlRMutexPtr xmlLibraryLock = NULL;
|
---|
121 |
|
---|
122 | /**
|
---|
123 | * xmlInitMutex:
|
---|
124 | * @mutex: the mutex
|
---|
125 | *
|
---|
126 | * Initialize a mutex.
|
---|
127 | */
|
---|
128 | void
|
---|
129 | xmlInitMutex(xmlMutexPtr mutex)
|
---|
130 | {
|
---|
131 | #ifdef HAVE_POSIX_THREADS
|
---|
132 | if (XML_IS_NEVER_THREADED() == 0)
|
---|
133 | pthread_mutex_init(&mutex->lock, NULL);
|
---|
134 | #elif defined HAVE_WIN32_THREADS
|
---|
135 | InitializeCriticalSection(&mutex->cs);
|
---|
136 | #else
|
---|
137 | (void) mutex;
|
---|
138 | #endif
|
---|
139 | }
|
---|
140 |
|
---|
141 | /**
|
---|
142 | * xmlNewMutex:
|
---|
143 | *
|
---|
144 | * xmlNewMutex() is used to allocate a libxml2 token struct for use in
|
---|
145 | * synchronizing access to data.
|
---|
146 | *
|
---|
147 | * Returns a new simple mutex pointer or NULL in case of error
|
---|
148 | */
|
---|
149 | xmlMutexPtr
|
---|
150 | xmlNewMutex(void)
|
---|
151 | {
|
---|
152 | xmlMutexPtr tok;
|
---|
153 |
|
---|
154 | if ((tok = malloc(sizeof(xmlMutex))) == NULL)
|
---|
155 | return (NULL);
|
---|
156 | xmlInitMutex(tok);
|
---|
157 | return (tok);
|
---|
158 | }
|
---|
159 |
|
---|
160 | /**
|
---|
161 | * xmlCleanupMutex:
|
---|
162 | * @mutex: the simple mutex
|
---|
163 | *
|
---|
164 | * Reclaim resources associated with a mutex.
|
---|
165 | */
|
---|
166 | void
|
---|
167 | xmlCleanupMutex(xmlMutexPtr mutex)
|
---|
168 | {
|
---|
169 | #ifdef HAVE_POSIX_THREADS
|
---|
170 | if (XML_IS_NEVER_THREADED() == 0)
|
---|
171 | pthread_mutex_destroy(&mutex->lock);
|
---|
172 | #elif defined HAVE_WIN32_THREADS
|
---|
173 | DeleteCriticalSection(&mutex->cs);
|
---|
174 | #else
|
---|
175 | (void) mutex;
|
---|
176 | #endif
|
---|
177 | }
|
---|
178 |
|
---|
179 | /**
|
---|
180 | * xmlFreeMutex:
|
---|
181 | * @tok: the simple mutex
|
---|
182 | *
|
---|
183 | * Free a mutex.
|
---|
184 | */
|
---|
185 | void
|
---|
186 | xmlFreeMutex(xmlMutexPtr tok)
|
---|
187 | {
|
---|
188 | if (tok == NULL)
|
---|
189 | return;
|
---|
190 |
|
---|
191 | xmlCleanupMutex(tok);
|
---|
192 | free(tok);
|
---|
193 | }
|
---|
194 |
|
---|
195 | /**
|
---|
196 | * xmlMutexLock:
|
---|
197 | * @tok: the simple mutex
|
---|
198 | *
|
---|
199 | * xmlMutexLock() is used to lock a libxml2 token.
|
---|
200 | */
|
---|
201 | void
|
---|
202 | xmlMutexLock(xmlMutexPtr tok)
|
---|
203 | {
|
---|
204 | if (tok == NULL)
|
---|
205 | return;
|
---|
206 | #ifdef HAVE_POSIX_THREADS
|
---|
207 | /*
|
---|
208 | * This assumes that __libc_single_threaded won't change while the
|
---|
209 | * lock is held.
|
---|
210 | */
|
---|
211 | if (XML_IS_THREADED() != 0)
|
---|
212 | pthread_mutex_lock(&tok->lock);
|
---|
213 | #elif defined HAVE_WIN32_THREADS
|
---|
214 | EnterCriticalSection(&tok->cs);
|
---|
215 | #endif
|
---|
216 |
|
---|
217 | }
|
---|
218 |
|
---|
219 | /**
|
---|
220 | * xmlMutexUnlock:
|
---|
221 | * @tok: the simple mutex
|
---|
222 | *
|
---|
223 | * xmlMutexUnlock() is used to unlock a libxml2 token.
|
---|
224 | */
|
---|
225 | void
|
---|
226 | xmlMutexUnlock(xmlMutexPtr tok)
|
---|
227 | {
|
---|
228 | if (tok == NULL)
|
---|
229 | return;
|
---|
230 | #ifdef HAVE_POSIX_THREADS
|
---|
231 | if (XML_IS_THREADED() != 0)
|
---|
232 | pthread_mutex_unlock(&tok->lock);
|
---|
233 | #elif defined HAVE_WIN32_THREADS
|
---|
234 | LeaveCriticalSection(&tok->cs);
|
---|
235 | #endif
|
---|
236 | }
|
---|
237 |
|
---|
238 | /**
|
---|
239 | * xmlNewRMutex:
|
---|
240 | *
|
---|
241 | * xmlRNewMutex() is used to allocate a reentrant mutex for use in
|
---|
242 | * synchronizing access to data. token_r is a re-entrant lock and thus useful
|
---|
243 | * for synchronizing access to data structures that may be manipulated in a
|
---|
244 | * recursive fashion.
|
---|
245 | *
|
---|
246 | * Returns the new reentrant mutex pointer or NULL in case of error
|
---|
247 | */
|
---|
248 | xmlRMutexPtr
|
---|
249 | xmlNewRMutex(void)
|
---|
250 | {
|
---|
251 | xmlRMutexPtr tok;
|
---|
252 |
|
---|
253 | if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
|
---|
254 | return (NULL);
|
---|
255 | #ifdef HAVE_POSIX_THREADS
|
---|
256 | if (XML_IS_NEVER_THREADED() == 0) {
|
---|
257 | pthread_mutex_init(&tok->lock, NULL);
|
---|
258 | tok->held = 0;
|
---|
259 | tok->waiters = 0;
|
---|
260 | pthread_cond_init(&tok->cv, NULL);
|
---|
261 | }
|
---|
262 | #elif defined HAVE_WIN32_THREADS
|
---|
263 | InitializeCriticalSection(&tok->cs);
|
---|
264 | #endif
|
---|
265 | return (tok);
|
---|
266 | }
|
---|
267 |
|
---|
268 | /**
|
---|
269 | * xmlFreeRMutex:
|
---|
270 | * @tok: the reentrant mutex
|
---|
271 | *
|
---|
272 | * xmlRFreeMutex() is used to reclaim resources associated with a
|
---|
273 | * reentrant mutex.
|
---|
274 | */
|
---|
275 | void
|
---|
276 | xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
|
---|
277 | {
|
---|
278 | if (tok == NULL)
|
---|
279 | return;
|
---|
280 | #ifdef HAVE_POSIX_THREADS
|
---|
281 | if (XML_IS_NEVER_THREADED() == 0) {
|
---|
282 | pthread_mutex_destroy(&tok->lock);
|
---|
283 | pthread_cond_destroy(&tok->cv);
|
---|
284 | }
|
---|
285 | #elif defined HAVE_WIN32_THREADS
|
---|
286 | DeleteCriticalSection(&tok->cs);
|
---|
287 | #endif
|
---|
288 | free(tok);
|
---|
289 | }
|
---|
290 |
|
---|
291 | /**
|
---|
292 | * xmlRMutexLock:
|
---|
293 | * @tok: the reentrant mutex
|
---|
294 | *
|
---|
295 | * xmlRMutexLock() is used to lock a libxml2 token_r.
|
---|
296 | */
|
---|
297 | void
|
---|
298 | xmlRMutexLock(xmlRMutexPtr tok)
|
---|
299 | {
|
---|
300 | if (tok == NULL)
|
---|
301 | return;
|
---|
302 | #ifdef HAVE_POSIX_THREADS
|
---|
303 | if (XML_IS_THREADED() == 0)
|
---|
304 | return;
|
---|
305 |
|
---|
306 | pthread_mutex_lock(&tok->lock);
|
---|
307 | if (tok->held) {
|
---|
308 | if (pthread_equal(tok->tid, pthread_self())) {
|
---|
309 | tok->held++;
|
---|
310 | pthread_mutex_unlock(&tok->lock);
|
---|
311 | return;
|
---|
312 | } else {
|
---|
313 | tok->waiters++;
|
---|
314 | while (tok->held)
|
---|
315 | pthread_cond_wait(&tok->cv, &tok->lock);
|
---|
316 | tok->waiters--;
|
---|
317 | }
|
---|
318 | }
|
---|
319 | tok->tid = pthread_self();
|
---|
320 | tok->held = 1;
|
---|
321 | pthread_mutex_unlock(&tok->lock);
|
---|
322 | #elif defined HAVE_WIN32_THREADS
|
---|
323 | EnterCriticalSection(&tok->cs);
|
---|
324 | #endif
|
---|
325 | }
|
---|
326 |
|
---|
327 | /**
|
---|
328 | * xmlRMutexUnlock:
|
---|
329 | * @tok: the reentrant mutex
|
---|
330 | *
|
---|
331 | * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
|
---|
332 | */
|
---|
333 | void
|
---|
334 | xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
|
---|
335 | {
|
---|
336 | if (tok == NULL)
|
---|
337 | return;
|
---|
338 | #ifdef HAVE_POSIX_THREADS
|
---|
339 | if (XML_IS_THREADED() == 0)
|
---|
340 | return;
|
---|
341 |
|
---|
342 | pthread_mutex_lock(&tok->lock);
|
---|
343 | tok->held--;
|
---|
344 | if (tok->held == 0) {
|
---|
345 | if (tok->waiters)
|
---|
346 | pthread_cond_signal(&tok->cv);
|
---|
347 | memset(&tok->tid, 0, sizeof(tok->tid));
|
---|
348 | }
|
---|
349 | pthread_mutex_unlock(&tok->lock);
|
---|
350 | #elif defined HAVE_WIN32_THREADS
|
---|
351 | LeaveCriticalSection(&tok->cs);
|
---|
352 | #endif
|
---|
353 | }
|
---|
354 |
|
---|
355 | /************************************************************************
|
---|
356 | * *
|
---|
357 | * Library wide thread interfaces *
|
---|
358 | * *
|
---|
359 | ************************************************************************/
|
---|
360 |
|
---|
361 | /**
|
---|
362 | * xmlGetThreadId:
|
---|
363 | *
|
---|
364 | * DEPRECATED: Internal function, do not use.
|
---|
365 | *
|
---|
366 | * xmlGetThreadId() find the current thread ID number
|
---|
367 | * Note that this is likely to be broken on some platforms using pthreads
|
---|
368 | * as the specification doesn't mandate pthread_t to be an integer type
|
---|
369 | *
|
---|
370 | * Returns the current thread ID number
|
---|
371 | */
|
---|
372 | int
|
---|
373 | xmlGetThreadId(void)
|
---|
374 | {
|
---|
375 | #ifdef HAVE_POSIX_THREADS
|
---|
376 | pthread_t id;
|
---|
377 | int ret;
|
---|
378 |
|
---|
379 | if (XML_IS_THREADED() == 0)
|
---|
380 | return (0);
|
---|
381 | id = pthread_self();
|
---|
382 | /* horrible but preserves compat, see warning above */
|
---|
383 | memcpy(&ret, &id, sizeof(ret));
|
---|
384 | return (ret);
|
---|
385 | #elif defined HAVE_WIN32_THREADS
|
---|
386 | return GetCurrentThreadId();
|
---|
387 | #else
|
---|
388 | return ((int) 0);
|
---|
389 | #endif
|
---|
390 | }
|
---|
391 |
|
---|
392 | /**
|
---|
393 | * xmlLockLibrary:
|
---|
394 | *
|
---|
395 | * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
|
---|
396 | * library.
|
---|
397 | */
|
---|
398 | void
|
---|
399 | xmlLockLibrary(void)
|
---|
400 | {
|
---|
401 | xmlRMutexLock(xmlLibraryLock);
|
---|
402 | }
|
---|
403 |
|
---|
404 | /**
|
---|
405 | * xmlUnlockLibrary:
|
---|
406 | *
|
---|
407 | * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
|
---|
408 | * library.
|
---|
409 | */
|
---|
410 | void
|
---|
411 | xmlUnlockLibrary(void)
|
---|
412 | {
|
---|
413 | xmlRMutexUnlock(xmlLibraryLock);
|
---|
414 | }
|
---|
415 |
|
---|
416 | /**
|
---|
417 | * xmlInitThreads:
|
---|
418 | *
|
---|
419 | * DEPRECATED: Alias for xmlInitParser.
|
---|
420 | */
|
---|
421 | void
|
---|
422 | xmlInitThreads(void)
|
---|
423 | {
|
---|
424 | xmlInitParser();
|
---|
425 | }
|
---|
426 |
|
---|
427 | /**
|
---|
428 | * xmlCleanupThreads:
|
---|
429 | *
|
---|
430 | * DEPRECATED: This function is a no-op. Call xmlCleanupParser
|
---|
431 | * to free global state but see the warnings there. xmlCleanupParser
|
---|
432 | * should be only called once at program exit. In most cases, you don't
|
---|
433 | * have call cleanup functions at all.
|
---|
434 | */
|
---|
435 | void
|
---|
436 | xmlCleanupThreads(void)
|
---|
437 | {
|
---|
438 | }
|
---|
439 |
|
---|
440 | /************************************************************************
|
---|
441 | * *
|
---|
442 | * Library wide initialization *
|
---|
443 | * *
|
---|
444 | ************************************************************************/
|
---|
445 |
|
---|
446 | static int xmlParserInitialized = 0;
|
---|
447 | static int xmlParserInnerInitialized = 0;
|
---|
448 |
|
---|
449 |
|
---|
450 | #ifdef HAVE_POSIX_THREADS
|
---|
451 | static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
|
---|
452 | #elif defined HAVE_WIN32_THREADS
|
---|
453 | static volatile LPCRITICAL_SECTION global_init_lock = NULL;
|
---|
454 | #endif
|
---|
455 |
|
---|
456 | /**
|
---|
457 | * xmlGlobalInitMutexLock
|
---|
458 | *
|
---|
459 | * Makes sure that the global initialization mutex is initialized and
|
---|
460 | * locks it.
|
---|
461 | */
|
---|
462 | static void
|
---|
463 | xmlGlobalInitMutexLock(void) {
|
---|
464 | #ifdef HAVE_POSIX_THREADS
|
---|
465 |
|
---|
466 | #ifdef XML_PTHREAD_WEAK
|
---|
467 | /*
|
---|
468 | * This is somewhat unreliable since libpthread could be loaded
|
---|
469 | * later with dlopen() and threads could be created. But it's
|
---|
470 | * long-standing behavior and hard to work around.
|
---|
471 | */
|
---|
472 | if (libxml_is_threaded == -1)
|
---|
473 | libxml_is_threaded =
|
---|
474 | (pthread_mutex_init != NULL) &&
|
---|
475 | (pthread_mutex_destroy != NULL) &&
|
---|
476 | (pthread_mutex_lock != NULL) &&
|
---|
477 | (pthread_mutex_unlock != NULL) &&
|
---|
478 | (pthread_cond_init != NULL) &&
|
---|
479 | (pthread_cond_destroy != NULL) &&
|
---|
480 | (pthread_cond_wait != NULL) &&
|
---|
481 | /*
|
---|
482 | * pthread_equal can be inline, resuting in -Waddress warnings.
|
---|
483 | * Let's assume it's available if all the other functions are.
|
---|
484 | */
|
---|
485 | /* (pthread_equal != NULL) && */
|
---|
486 | (pthread_self != NULL) &&
|
---|
487 | (pthread_cond_signal != NULL);
|
---|
488 | #endif
|
---|
489 |
|
---|
490 | /* The mutex is statically initialized, so we just lock it. */
|
---|
491 | if (XML_IS_THREADED() != 0)
|
---|
492 | pthread_mutex_lock(&global_init_lock);
|
---|
493 |
|
---|
494 | #elif defined HAVE_WIN32_THREADS
|
---|
495 |
|
---|
496 | LPCRITICAL_SECTION cs;
|
---|
497 |
|
---|
498 | /* Create a new critical section */
|
---|
499 | if (global_init_lock == NULL) {
|
---|
500 | cs = malloc(sizeof(CRITICAL_SECTION));
|
---|
501 | if (cs == NULL) {
|
---|
502 | fprintf(stderr, "libxml2: xmlInitParser: out of memory\n");
|
---|
503 | abort();
|
---|
504 | }
|
---|
505 | InitializeCriticalSection(cs);
|
---|
506 |
|
---|
507 | /* Swap it into the global_init_lock */
|
---|
508 | #ifdef InterlockedCompareExchangePointer
|
---|
509 | InterlockedCompareExchangePointer((void **) &global_init_lock,
|
---|
510 | cs, NULL);
|
---|
511 | #else /* Use older void* version */
|
---|
512 | InterlockedCompareExchange((void **) &global_init_lock,
|
---|
513 | (void *) cs, NULL);
|
---|
514 | #endif /* InterlockedCompareExchangePointer */
|
---|
515 |
|
---|
516 | /* If another thread successfully recorded its critical
|
---|
517 | * section in the global_init_lock then discard the one
|
---|
518 | * allocated by this thread. */
|
---|
519 | if (global_init_lock != cs) {
|
---|
520 | DeleteCriticalSection(cs);
|
---|
521 | free(cs);
|
---|
522 | }
|
---|
523 | }
|
---|
524 |
|
---|
525 | /* Lock the chosen critical section */
|
---|
526 | EnterCriticalSection(global_init_lock);
|
---|
527 |
|
---|
528 | #endif
|
---|
529 | }
|
---|
530 |
|
---|
531 | static void
|
---|
532 | xmlGlobalInitMutexUnlock(void) {
|
---|
533 | #ifdef HAVE_POSIX_THREADS
|
---|
534 | if (XML_IS_THREADED() != 0)
|
---|
535 | pthread_mutex_unlock(&global_init_lock);
|
---|
536 | #elif defined HAVE_WIN32_THREADS
|
---|
537 | if (global_init_lock != NULL)
|
---|
538 | LeaveCriticalSection(global_init_lock);
|
---|
539 | #endif
|
---|
540 | }
|
---|
541 |
|
---|
542 | /**
|
---|
543 | * xmlGlobalInitMutexDestroy
|
---|
544 | *
|
---|
545 | * Makes sure that the global initialization mutex is destroyed before
|
---|
546 | * application termination.
|
---|
547 | */
|
---|
548 | static void
|
---|
549 | xmlGlobalInitMutexDestroy(void) {
|
---|
550 | #ifdef HAVE_POSIX_THREADS
|
---|
551 | #elif defined HAVE_WIN32_THREADS
|
---|
552 | if (global_init_lock != NULL) {
|
---|
553 | DeleteCriticalSection(global_init_lock);
|
---|
554 | free(global_init_lock);
|
---|
555 | global_init_lock = NULL;
|
---|
556 | }
|
---|
557 | #endif
|
---|
558 | }
|
---|
559 |
|
---|
560 | /**
|
---|
561 | * xmlInitParser:
|
---|
562 | *
|
---|
563 | * Initialization function for the XML parser.
|
---|
564 | *
|
---|
565 | * Call once from the main thread before using the library in
|
---|
566 | * multithreaded programs.
|
---|
567 | */
|
---|
568 | void
|
---|
569 | xmlInitParser(void) {
|
---|
570 | /*
|
---|
571 | * Note that the initialization code must not make memory allocations.
|
---|
572 | */
|
---|
573 | if (xmlParserInitialized != 0)
|
---|
574 | return;
|
---|
575 |
|
---|
576 | xmlGlobalInitMutexLock();
|
---|
577 |
|
---|
578 | if (xmlParserInnerInitialized == 0) {
|
---|
579 | #if defined(_WIN32) && \
|
---|
580 | !defined(LIBXML_THREAD_ALLOC_ENABLED) && \
|
---|
581 | (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
|
---|
582 | if (xmlFree == free)
|
---|
583 | atexit(xmlCleanupParser);
|
---|
584 | #endif
|
---|
585 |
|
---|
586 | #ifndef VBOX
|
---|
587 | xmlInitRandom(); /* Required by xmlInitGlobalsInternal */
|
---|
588 | #endif
|
---|
589 | xmlInitMemoryInternal();
|
---|
590 | xmlInitGlobalsInternal();
|
---|
591 | xmlInitDictInternal();
|
---|
592 | xmlInitEncodingInternal();
|
---|
593 | #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
|
---|
594 | xmlInitXPathInternal();
|
---|
595 | #endif
|
---|
596 | xmlInitIOCallbacks();
|
---|
597 |
|
---|
598 | xmlParserInnerInitialized = 1;
|
---|
599 | }
|
---|
600 |
|
---|
601 | xmlGlobalInitMutexUnlock();
|
---|
602 |
|
---|
603 | xmlParserInitialized = 1;
|
---|
604 | }
|
---|
605 |
|
---|
606 | /**
|
---|
607 | * xmlCleanupParser:
|
---|
608 | *
|
---|
609 | * This function name is somewhat misleading. It does not clean up
|
---|
610 | * parser state, it cleans up memory allocated by the library itself.
|
---|
611 | * It is a cleanup function for the XML library. It tries to reclaim all
|
---|
612 | * related global memory allocated for the library processing.
|
---|
613 | * It doesn't deallocate any document related memory. One should
|
---|
614 | * call xmlCleanupParser() only when the process has finished using
|
---|
615 | * the library and all XML/HTML documents built with it.
|
---|
616 | * See also xmlInitParser() which has the opposite function of preparing
|
---|
617 | * the library for operations.
|
---|
618 | *
|
---|
619 | * WARNING: if your application is multithreaded or has plugin support
|
---|
620 | * calling this may crash the application if another thread or
|
---|
621 | * a plugin is still using libxml2. It's sometimes very hard to
|
---|
622 | * guess if libxml2 is in use in the application, some libraries
|
---|
623 | * or plugins may use it without notice. In case of doubt abstain
|
---|
624 | * from calling this function or do it just before calling exit()
|
---|
625 | * to avoid leak reports from valgrind !
|
---|
626 | */
|
---|
627 | void
|
---|
628 | xmlCleanupParser(void) {
|
---|
629 | if (!xmlParserInitialized)
|
---|
630 | return;
|
---|
631 |
|
---|
632 | /* These functions can call xmlFree. */
|
---|
633 |
|
---|
634 | xmlCleanupCharEncodingHandlers();
|
---|
635 | #ifdef LIBXML_CATALOG_ENABLED
|
---|
636 | xmlCatalogCleanup();
|
---|
637 | #endif
|
---|
638 | #ifdef LIBXML_SCHEMAS_ENABLED
|
---|
639 | xmlSchemaCleanupTypes();
|
---|
640 | xmlRelaxNGCleanupTypes();
|
---|
641 | #endif
|
---|
642 |
|
---|
643 | /* These functions should never call xmlFree. */
|
---|
644 |
|
---|
645 | xmlCleanupDictInternal();
|
---|
646 | #ifndef VBOX
|
---|
647 | xmlCleanupRandom();
|
---|
648 | #endif
|
---|
649 | xmlCleanupGlobalsInternal();
|
---|
650 | /*
|
---|
651 | * Must come last. On Windows, xmlCleanupGlobalsInternal can call
|
---|
652 | * xmlFree which uses xmlMemMutex in debug mode.
|
---|
653 | */
|
---|
654 | xmlCleanupMemoryInternal();
|
---|
655 |
|
---|
656 | xmlGlobalInitMutexDestroy();
|
---|
657 |
|
---|
658 | xmlParserInitialized = 0;
|
---|
659 | xmlParserInnerInitialized = 0;
|
---|
660 | }
|
---|
661 |
|
---|
662 | #if defined(HAVE_ATTRIBUTE_DESTRUCTOR) && \
|
---|
663 | !defined(LIBXML_THREAD_ALLOC_ENABLED) && \
|
---|
664 | !defined(LIBXML_STATIC) && \
|
---|
665 | !defined(_WIN32)
|
---|
666 | static void
|
---|
667 | ATTRIBUTE_DESTRUCTOR
|
---|
668 | xmlDestructor(void) {
|
---|
669 | /*
|
---|
670 | * Calling custom deallocation functions in a destructor can cause
|
---|
671 | * problems, for example with Nokogiri.
|
---|
672 | */
|
---|
673 | if (xmlFree == free)
|
---|
674 | xmlCleanupParser();
|
---|
675 | }
|
---|
676 | #endif
|
---|
677 |
|
---|