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

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;
1.1.1.2 ! misho     149: static pthread_once_t once_control_init = PTHREAD_ONCE_INIT;
1.1       misho     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. */
1.1.1.2 ! misho     442:     if (pthread_mutex_lock != NULL)
1.1       misho     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
1.1.1.2 ! misho     511:     if (pthread_mutex_unlock != NULL)
1.1       misho     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);
1.1.1.2 ! misho     917:     once_control = once_control_init;
1.1       misho     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();
1.1.1.2 ! misho     957:     __xmlInitializeDict();
1.1       misho     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();
1.1.1.2 ! misho     965:            __xmlInitializeDict();
1.1       misho     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);
1.1.1.2 ! misho     979:        __xmlInitializeDict();
1.1       misho     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>