Annotation of embedaddon/libxml2/threads.c, revision 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>