File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / threads.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 19:53:29 2014 UTC (10 years ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_9_1p0, v2_9_1, HEAD
libxml2 2.9.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>