File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / threads.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:37:57 2012 UTC (12 years, 5 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_8_0p0, v2_8_0, v2_7_8, HEAD
libxml2

    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_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
  150: #elif defined HAVE_WIN32_THREADS
  151: #if defined(HAVE_COMPILER_TLS)
  152: static __declspec(thread) xmlGlobalState tlstate;
  153: static __declspec(thread) int tlstate_inited = 0;
  154: #else /* HAVE_COMPILER_TLS */
  155: static DWORD globalkey = TLS_OUT_OF_INDEXES;
  156: #endif /* HAVE_COMPILER_TLS */
  157: static DWORD mainthread;
  158: static struct {
  159:     DWORD done;
  160:     DWORD control;
  161: } run_once = { 0, 0};
  162: static volatile LPCRITICAL_SECTION global_init_lock = NULL;
  163: 
  164: /* endif HAVE_WIN32_THREADS */
  165: #elif defined HAVE_BEOS_THREADS
  166: int32 globalkey = 0;
  167: thread_id mainthread = 0;
  168: int32 run_once_init = 0;
  169: static int32 global_init_lock = -1;
  170: static vint32 global_init_count = 0;
  171: #endif
  172: 
  173: static xmlRMutexPtr xmlLibraryLock = NULL;
  174: 
  175: #ifdef LIBXML_THREAD_ENABLED
  176: static void xmlOnceInit(void);
  177: #endif
  178: 
  179: /**
  180:  * xmlNewMutex:
  181:  *
  182:  * xmlNewMutex() is used to allocate a libxml2 token struct for use in
  183:  * synchronizing access to data.
  184:  *
  185:  * Returns a new simple mutex pointer or NULL in case of error
  186:  */
  187: xmlMutexPtr
  188: xmlNewMutex(void)
  189: {
  190:     xmlMutexPtr tok;
  191: 
  192:     if ((tok = malloc(sizeof(xmlMutex))) == NULL)
  193:         return (NULL);
  194: #ifdef HAVE_PTHREAD_H
  195:     if (libxml_is_threaded != 0)
  196:         pthread_mutex_init(&tok->lock, NULL);
  197: #elif defined HAVE_WIN32_THREADS
  198:     tok->mutex = CreateMutex(NULL, FALSE, NULL);
  199: #elif defined HAVE_BEOS_THREADS
  200:     if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) {
  201:         free(tok);
  202:         return NULL;
  203:     }
  204:     tok->tid = -1;
  205: #endif
  206:     return (tok);
  207: }
  208: 
  209: /**
  210:  * xmlFreeMutex:
  211:  * @tok:  the simple mutex
  212:  *
  213:  * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
  214:  * struct.
  215:  */
  216: void
  217: xmlFreeMutex(xmlMutexPtr tok)
  218: {
  219:     if (tok == NULL)
  220:         return;
  221: 
  222: #ifdef HAVE_PTHREAD_H
  223:     if (libxml_is_threaded != 0)
  224:         pthread_mutex_destroy(&tok->lock);
  225: #elif defined HAVE_WIN32_THREADS
  226:     CloseHandle(tok->mutex);
  227: #elif defined HAVE_BEOS_THREADS
  228:     delete_sem(tok->sem);
  229: #endif
  230:     free(tok);
  231: }
  232: 
  233: /**
  234:  * xmlMutexLock:
  235:  * @tok:  the simple mutex
  236:  *
  237:  * xmlMutexLock() is used to lock a libxml2 token.
  238:  */
  239: void
  240: xmlMutexLock(xmlMutexPtr tok)
  241: {
  242:     if (tok == NULL)
  243:         return;
  244: #ifdef HAVE_PTHREAD_H
  245:     if (libxml_is_threaded != 0)
  246:         pthread_mutex_lock(&tok->lock);
  247: #elif defined HAVE_WIN32_THREADS
  248:     WaitForSingleObject(tok->mutex, INFINITE);
  249: #elif defined HAVE_BEOS_THREADS
  250:     if (acquire_sem(tok->sem) != B_NO_ERROR) {
  251: #ifdef DEBUG_THREADS
  252:         xmlGenericError(xmlGenericErrorContext,
  253:                         "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
  254:         exit();
  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)
  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:         exit();
  503: #endif
  504:     }
  505: #endif
  506: }
  507: 
  508: void
  509: __xmlGlobalInitMutexUnlock(void)
  510: {
  511: #ifdef HAVE_PTHREAD_H
  512:     if (pthread_mutex_unlock)
  513:         pthread_mutex_unlock(&global_init_lock);
  514: #elif defined HAVE_WIN32_THREADS
  515:     if (global_init_lock != NULL) {
  516: 	LeaveCriticalSection(global_init_lock);
  517:     }
  518: #elif defined HAVE_BEOS_THREADS
  519:     release_sem(global_init_lock);
  520: #endif
  521: }
  522: 
  523: /**
  524:  * xmlGlobalInitMutexDestroy
  525:  *
  526:  * Makes sure that the global initialization mutex is destroyed before
  527:  * application termination.
  528:  */
  529: void
  530: __xmlGlobalInitMutexDestroy(void)
  531: {
  532: #ifdef HAVE_PTHREAD_H
  533: #elif defined HAVE_WIN32_THREADS
  534:     if (global_init_lock != NULL) {
  535:         DeleteCriticalSection(global_init_lock);
  536:         free(global_init_lock);
  537:         global_init_lock = NULL;
  538:     }
  539: #endif
  540: }
  541: 
  542: /************************************************************************
  543:  *									*
  544:  *			Per thread global state handling		*
  545:  *									*
  546:  ************************************************************************/
  547: 
  548: #ifdef LIBXML_THREAD_ENABLED
  549: #ifdef xmlLastError
  550: #undef xmlLastError
  551: #endif
  552: 
  553: /**
  554:  * xmlFreeGlobalState:
  555:  * @state:  a thread global state
  556:  *
  557:  * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
  558:  * global state. It is is used here to reclaim memory resources.
  559:  */
  560: static void
  561: xmlFreeGlobalState(void *state)
  562: {
  563:     xmlGlobalState *gs = (xmlGlobalState *) state;
  564: 
  565:     /* free any memory allocated in the thread's xmlLastError */
  566:     xmlResetError(&(gs->xmlLastError));
  567:     free(state);
  568: }
  569: 
  570: /**
  571:  * xmlNewGlobalState:
  572:  *
  573:  * xmlNewGlobalState() allocates a global state. This structure is used to
  574:  * hold all data for use by a thread when supporting backwards compatibility
  575:  * of libxml2 to pre-thread-safe behaviour.
  576:  *
  577:  * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
  578:  */
  579: static xmlGlobalStatePtr
  580: xmlNewGlobalState(void)
  581: {
  582:     xmlGlobalState *gs;
  583: 
  584:     gs = malloc(sizeof(xmlGlobalState));
  585:     if (gs == NULL) {
  586: 	xmlGenericError(xmlGenericErrorContext,
  587: 			"xmlGetGlobalState: out of memory\n");
  588:         return (NULL);
  589:     }
  590: 
  591:     memset(gs, 0, sizeof(xmlGlobalState));
  592:     xmlInitializeGlobalState(gs);
  593:     return (gs);
  594: }
  595: #endif /* LIBXML_THREAD_ENABLED */
  596: 
  597: #ifdef HAVE_PTHREAD_H
  598: #elif defined HAVE_WIN32_THREADS
  599: #if !defined(HAVE_COMPILER_TLS)
  600: #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
  601: typedef struct _xmlGlobalStateCleanupHelperParams {
  602:     HANDLE thread;
  603:     void *memory;
  604: } xmlGlobalStateCleanupHelperParams;
  605: 
  606: static void XMLCDECL
  607: xmlGlobalStateCleanupHelper(void *p)
  608: {
  609:     xmlGlobalStateCleanupHelperParams *params =
  610:         (xmlGlobalStateCleanupHelperParams *) p;
  611:     WaitForSingleObject(params->thread, INFINITE);
  612:     CloseHandle(params->thread);
  613:     xmlFreeGlobalState(params->memory);
  614:     free(params);
  615:     _endthread();
  616: }
  617: #else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
  618: 
  619: typedef struct _xmlGlobalStateCleanupHelperParams {
  620:     void *memory;
  621:     struct _xmlGlobalStateCleanupHelperParams *prev;
  622:     struct _xmlGlobalStateCleanupHelperParams *next;
  623: } xmlGlobalStateCleanupHelperParams;
  624: 
  625: static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL;
  626: static CRITICAL_SECTION cleanup_helpers_cs;
  627: 
  628: #endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
  629: #endif /* HAVE_COMPILER_TLS */
  630: #endif /* HAVE_WIN32_THREADS */
  631: 
  632: #if defined HAVE_BEOS_THREADS
  633: 
  634: /**
  635:  * xmlGlobalStateCleanup:
  636:  * @data: unused parameter
  637:  *
  638:  * Used for Beos only
  639:  */
  640: void
  641: xmlGlobalStateCleanup(void *data)
  642: {
  643:     void *globalval = tls_get(globalkey);
  644: 
  645:     if (globalval != NULL)
  646:         xmlFreeGlobalState(globalval);
  647: }
  648: #endif
  649: 
  650: /**
  651:  * xmlGetGlobalState:
  652:  *
  653:  * xmlGetGlobalState() is called to retrieve the global state for a thread.
  654:  *
  655:  * Returns the thread global state or NULL in case of error
  656:  */
  657: xmlGlobalStatePtr
  658: xmlGetGlobalState(void)
  659: {
  660: #ifdef HAVE_PTHREAD_H
  661:     xmlGlobalState *globalval;
  662: 
  663:     if (libxml_is_threaded == 0)
  664:         return (NULL);
  665: 
  666:     pthread_once(&once_control, xmlOnceInit);
  667: 
  668:     if ((globalval = (xmlGlobalState *)
  669:          pthread_getspecific(globalkey)) == NULL) {
  670:         xmlGlobalState *tsd = xmlNewGlobalState();
  671: 	if (tsd == NULL)
  672: 	    return(NULL);
  673: 
  674:         pthread_setspecific(globalkey, tsd);
  675:         return (tsd);
  676:     }
  677:     return (globalval);
  678: #elif defined HAVE_WIN32_THREADS
  679: #if defined(HAVE_COMPILER_TLS)
  680:     if (!tlstate_inited) {
  681:         tlstate_inited = 1;
  682:         xmlInitializeGlobalState(&tlstate);
  683:     }
  684:     return &tlstate;
  685: #else /* HAVE_COMPILER_TLS */
  686:     xmlGlobalState *globalval;
  687:     xmlGlobalStateCleanupHelperParams *p;
  688: 
  689:     xmlOnceInit();
  690: #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
  691:     globalval = (xmlGlobalState *) TlsGetValue(globalkey);
  692: #else
  693:     p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey);
  694:     globalval = (xmlGlobalState *) (p ? p->memory : NULL);
  695: #endif
  696:     if (globalval == NULL) {
  697:         xmlGlobalState *tsd = xmlNewGlobalState();
  698: 
  699:         if (tsd == NULL)
  700: 	    return(NULL);
  701:         p = (xmlGlobalStateCleanupHelperParams *)
  702:             malloc(sizeof(xmlGlobalStateCleanupHelperParams));
  703: 	if (p == NULL) {
  704:             xmlGenericError(xmlGenericErrorContext,
  705:                             "xmlGetGlobalState: out of memory\n");
  706:             xmlFreeGlobalState(tsd);
  707: 	    return(NULL);
  708: 	}
  709:         p->memory = tsd;
  710: #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
  711:         DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
  712:                         GetCurrentProcess(), &p->thread, 0, TRUE,
  713:                         DUPLICATE_SAME_ACCESS);
  714:         TlsSetValue(globalkey, tsd);
  715:         _beginthread(xmlGlobalStateCleanupHelper, 0, p);
  716: #else
  717:         EnterCriticalSection(&cleanup_helpers_cs);
  718:         if (cleanup_helpers_head != NULL) {
  719:             cleanup_helpers_head->prev = p;
  720:         }
  721:         p->next = cleanup_helpers_head;
  722:         p->prev = NULL;
  723:         cleanup_helpers_head = p;
  724:         TlsSetValue(globalkey, p);
  725:         LeaveCriticalSection(&cleanup_helpers_cs);
  726: #endif
  727: 
  728:         return (tsd);
  729:     }
  730:     return (globalval);
  731: #endif /* HAVE_COMPILER_TLS */
  732: #elif defined HAVE_BEOS_THREADS
  733:     xmlGlobalState *globalval;
  734: 
  735:     xmlOnceInit();
  736: 
  737:     if ((globalval = (xmlGlobalState *) tls_get(globalkey)) == NULL) {
  738:         xmlGlobalState *tsd = xmlNewGlobalState();
  739: 	if (tsd == NULL)
  740: 	    return (NULL);
  741: 
  742:         tls_set(globalkey, tsd);
  743:         on_exit_thread(xmlGlobalStateCleanup, NULL);
  744:         return (tsd);
  745:     }
  746:     return (globalval);
  747: #else
  748:     return (NULL);
  749: #endif
  750: }
  751: 
  752: /************************************************************************
  753:  *									*
  754:  *			Library wide thread interfaces			*
  755:  *									*
  756:  ************************************************************************/
  757: 
  758: /**
  759:  * xmlGetThreadId:
  760:  *
  761:  * xmlGetThreadId() find the current thread ID number
  762:  * Note that this is likely to be broken on some platforms using pthreads
  763:  * as the specification doesn't mandate pthread_t to be an integer type
  764:  *
  765:  * Returns the current thread ID number
  766:  */
  767: int
  768: xmlGetThreadId(void)
  769: {
  770: #ifdef HAVE_PTHREAD_H
  771:     pthread_t id;
  772:     int ret;
  773: 
  774:     if (libxml_is_threaded == 0)
  775:         return (0);
  776:     id = pthread_self();
  777:     /* horrible but preserves compat, see warning above */
  778:     memcpy(&ret, &id, sizeof(ret));
  779:     return (ret);
  780: #elif defined HAVE_WIN32_THREADS
  781:     return GetCurrentThreadId();
  782: #elif defined HAVE_BEOS_THREADS
  783:     return find_thread(NULL);
  784: #else
  785:     return ((int) 0);
  786: #endif
  787: }
  788: 
  789: /**
  790:  * xmlIsMainThread:
  791:  *
  792:  * xmlIsMainThread() check whether the current thread is the main thread.
  793:  *
  794:  * Returns 1 if the current thread is the main thread, 0 otherwise
  795:  */
  796: int
  797: xmlIsMainThread(void)
  798: {
  799: #ifdef HAVE_PTHREAD_H
  800:     if (libxml_is_threaded == -1)
  801:         xmlInitThreads();
  802:     if (libxml_is_threaded == 0)
  803:         return (1);
  804:     pthread_once(&once_control, xmlOnceInit);
  805: #elif defined HAVE_WIN32_THREADS
  806:     xmlOnceInit();
  807: #elif defined HAVE_BEOS_THREADS
  808:     xmlOnceInit();
  809: #endif
  810: 
  811: #ifdef DEBUG_THREADS
  812:     xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
  813: #endif
  814: #ifdef HAVE_PTHREAD_H
  815:     return (pthread_equal(mainthread,pthread_self()));
  816: #elif defined HAVE_WIN32_THREADS
  817:     return (mainthread == GetCurrentThreadId());
  818: #elif defined HAVE_BEOS_THREADS
  819:     return (mainthread == find_thread(NULL));
  820: #else
  821:     return (1);
  822: #endif
  823: }
  824: 
  825: /**
  826:  * xmlLockLibrary:
  827:  *
  828:  * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
  829:  * library.
  830:  */
  831: void
  832: xmlLockLibrary(void)
  833: {
  834: #ifdef DEBUG_THREADS
  835:     xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
  836: #endif
  837:     xmlRMutexLock(xmlLibraryLock);
  838: }
  839: 
  840: /**
  841:  * xmlUnlockLibrary:
  842:  *
  843:  * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
  844:  * library.
  845:  */
  846: void
  847: xmlUnlockLibrary(void)
  848: {
  849: #ifdef DEBUG_THREADS
  850:     xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
  851: #endif
  852:     xmlRMutexUnlock(xmlLibraryLock);
  853: }
  854: 
  855: /**
  856:  * xmlInitThreads:
  857:  *
  858:  * xmlInitThreads() is used to to initialize all the thread related
  859:  * data of the libxml2 library.
  860:  */
  861: void
  862: xmlInitThreads(void)
  863: {
  864: #ifdef HAVE_PTHREAD_H
  865:     if (libxml_is_threaded == -1) {
  866:         if ((pthread_once != NULL) &&
  867:             (pthread_getspecific != NULL) &&
  868:             (pthread_setspecific != NULL) &&
  869:             (pthread_key_create != NULL) &&
  870:             (pthread_key_delete != NULL) &&
  871:             (pthread_mutex_init != NULL) &&
  872:             (pthread_mutex_destroy != NULL) &&
  873:             (pthread_mutex_lock != NULL) &&
  874:             (pthread_mutex_unlock != NULL) &&
  875:             (pthread_cond_init != NULL) &&
  876:             (pthread_cond_destroy != NULL) &&
  877:             (pthread_cond_wait != NULL) &&
  878:             (pthread_equal != NULL) &&
  879:             (pthread_self != NULL) &&
  880:             (pthread_cond_signal != NULL)) {
  881:             libxml_is_threaded = 1;
  882: 
  883: /* fprintf(stderr, "Running multithreaded\n"); */
  884:         } else {
  885: 
  886: /* fprintf(stderr, "Running without multithread\n"); */
  887:             libxml_is_threaded = 0;
  888:         }
  889:     }
  890: #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
  891:     InitializeCriticalSection(&cleanup_helpers_cs);
  892: #endif
  893: }
  894: 
  895: /**
  896:  * xmlCleanupThreads:
  897:  *
  898:  * xmlCleanupThreads() is used to to cleanup all the thread related
  899:  * data of the libxml2 library once processing has ended.
  900:  *
  901:  * WARNING: if your application is multithreaded or has plugin support
  902:  *          calling this may crash the application if another thread or
  903:  *          a plugin is still using libxml2. It's sometimes very hard to
  904:  *          guess if libxml2 is in use in the application, some libraries
  905:  *          or plugins may use it without notice. In case of doubt abstain
  906:  *          from calling this function or do it just before calling exit()
  907:  *          to avoid leak reports from valgrind !
  908:  */
  909: void
  910: xmlCleanupThreads(void)
  911: {
  912: #ifdef DEBUG_THREADS
  913:     xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
  914: #endif
  915: #ifdef HAVE_PTHREAD_H
  916:     if ((libxml_is_threaded)  && (pthread_key_delete != NULL))
  917:         pthread_key_delete(globalkey);
  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: #elif defined(HAVE_WIN32_THREADS)
  958:     if (!run_once.done) {
  959:         if (InterlockedIncrement(&run_once.control) == 1) {
  960: #if !defined(HAVE_COMPILER_TLS)
  961:             globalkey = TlsAlloc();
  962: #endif
  963:             mainthread = GetCurrentThreadId();
  964:             run_once.done = 1;
  965:         } else {
  966:             /* Another thread is working; give up our slice and
  967:              * wait until they're done. */
  968:             while (!run_once.done)
  969:                 Sleep(0);
  970:         }
  971:     }
  972: #elif defined HAVE_BEOS_THREADS
  973:     if (atomic_add(&run_once_init, 1) == 0) {
  974:         globalkey = tls_allocate();
  975:         tls_set(globalkey, NULL);
  976:         mainthread = find_thread(NULL);
  977:     } else
  978:         atomic_add(&run_once_init, -1);
  979: #endif
  980: }
  981: #endif
  982: 
  983: /**
  984:  * DllMain:
  985:  * @hinstDLL: handle to DLL instance
  986:  * @fdwReason: Reason code for entry
  987:  * @lpvReserved: generic pointer (depends upon reason code)
  988:  *
  989:  * Entry point for Windows library. It is being used to free thread-specific
  990:  * storage.
  991:  *
  992:  * Returns TRUE always
  993:  */
  994: #ifdef HAVE_PTHREAD_H
  995: #elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
  996: #if defined(LIBXML_STATIC_FOR_DLL)
  997: BOOL XMLCALL
  998: xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
  999: #else
 1000: BOOL WINAPI
 1001: DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 1002: #endif
 1003: {
 1004:     switch (fdwReason) {
 1005:         case DLL_THREAD_DETACH:
 1006:             if (globalkey != TLS_OUT_OF_INDEXES) {
 1007:                 xmlGlobalState *globalval = NULL;
 1008:                 xmlGlobalStateCleanupHelperParams *p =
 1009:                     (xmlGlobalStateCleanupHelperParams *)
 1010:                     TlsGetValue(globalkey);
 1011:                 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
 1012:                 if (globalval) {
 1013:                     xmlFreeGlobalState(globalval);
 1014:                     TlsSetValue(globalkey, NULL);
 1015:                 }
 1016:                 if (p) {
 1017:                     EnterCriticalSection(&cleanup_helpers_cs);
 1018:                     if (p == cleanup_helpers_head)
 1019:                         cleanup_helpers_head = p->next;
 1020:                     else
 1021:                         p->prev->next = p->next;
 1022:                     if (p->next != NULL)
 1023:                         p->next->prev = p->prev;
 1024:                     LeaveCriticalSection(&cleanup_helpers_cs);
 1025:                     free(p);
 1026:                 }
 1027:             }
 1028:             break;
 1029:     }
 1030:     return TRUE;
 1031: }
 1032: #endif
 1033: #define bottom_threads
 1034: #include "elfgcchack.h"

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