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