threads.c 26 KB

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