Annotation of embedaddon/libxml2/threads.c, revision 1.1.1.1

1.1       misho       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>