diff options
Diffstat (limited to 'unix/tclUnixThrd.c')
| -rw-r--r-- | unix/tclUnixThrd.c | 533 |
1 files changed, 205 insertions, 328 deletions
diff --git a/unix/tclUnixThrd.c b/unix/tclUnixThrd.c index 9587590..a7a294d 100644 --- a/unix/tclUnixThrd.c +++ b/unix/tclUnixThrd.c @@ -3,9 +3,8 @@ * * This file implements the UNIX-specific thread support. * - * Copyright © 1991-1994 The Regents of the University of California. - * Copyright © 1994-1997 Sun Microsystems, Inc. - * Copyright © 2008 George Peter Staplin + * Copyright (c) 1991-1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -13,192 +12,46 @@ #include "tclInt.h" -#if TCL_THREADS - -/* - * TIP #509. Ensures that Tcl's mutexes are reentrant. - * - *---------------------------------------------------------------------- - * - * PMutexInit -- - * - * Sets up the memory pointed to by its argument so that it contains the - * implementation of a recursive lock. Caller supplies the space. - * - *---------------------------------------------------------------------- - * - * PMutexDestroy -- - * - * Tears down the implementation of a recursive lock (but does not - * deallocate the space holding the lock). - * - *---------------------------------------------------------------------- - * - * PMutexLock -- - * - * Locks a recursive lock. (Similar to pthread_mutex_lock) - * - *---------------------------------------------------------------------- - * - * PMutexUnlock -- - * - * Unlocks a recursive lock. (Similar to pthread_mutex_unlock) - * - *---------------------------------------------------------------------- - * - * PCondWait -- - * - * Waits on a condition variable linked a recursive lock. (Similar to - * pthread_cond_wait) - * - *---------------------------------------------------------------------- - * - * PCondTimedWait -- - * - * Waits for a limited amount of time on a condition variable linked to a - * recursive lock. (Similar to pthread_cond_timedwait) - * - *---------------------------------------------------------------------- - */ - -#ifndef HAVE_DECL_PTHREAD_MUTEX_RECURSIVE -#define HAVE_DECL_PTHREAD_MUTEX_RECURSIVE 0 -#endif - -#if HAVE_DECL_PTHREAD_MUTEX_RECURSIVE -/* - * Pthread has native reentrant (AKA recursive) mutexes. Use them for - * Tcl_Mutex. - */ - -typedef pthread_mutex_t PMutex; - -static void -PMutexInit( - PMutex *pmutexPtr) -{ - pthread_mutexattr_t attr; - - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(pmutexPtr, &attr); -} - -#define PMutexDestroy pthread_mutex_destroy -#define PMutexLock pthread_mutex_lock -#define PMutexUnlock pthread_mutex_unlock -#define PCondWait pthread_cond_wait -#define PCondTimedWait pthread_cond_timedwait +#ifdef TCL_THREADS -#else /* !HAVE_PTHREAD_MUTEX_RECURSIVE */ - -/* - * No native support for reentrant mutexes. Emulate them with regular mutexes - * and thread-local counters. - */ - -typedef struct PMutex { - pthread_mutex_t mutex; - pthread_t thread; - int counter; -} PMutex; - -static void -PMutexInit( - PMutex *pmutexPtr) -{ - pthread_mutex_init(&pmutexPtr->mutex, NULL); - pmutexPtr->thread = 0; - pmutexPtr->counter = 0; -} - -static void -PMutexDestroy( - PMutex *pmutexPtr) -{ - pthread_mutex_destroy(&pmutexPtr->mutex); -} - -static void -PMutexLock( - PMutex *pmutexPtr) -{ - if (pmutexPtr->thread != pthread_self() || pmutexPtr->counter == 0) { - pthread_mutex_lock(&pmutexPtr->mutex); - pmutexPtr->thread = pthread_self(); - pmutexPtr->counter = 0; - } - pmutexPtr->counter++; -} - -static void -PMutexUnlock( - PMutex *pmutexPtr) -{ - pmutexPtr->counter--; - if (pmutexPtr->counter == 0) { - pmutexPtr->thread = 0; - pthread_mutex_unlock(&pmutexPtr->mutex); - } -} - -static void -PCondWait( - pthread_cond_t *pcondPtr, - PMutex *pmutexPtr) -{ - pthread_cond_wait(pcondPtr, &pmutexPtr->mutex); -} - -static void -PCondTimedWait( - pthread_cond_t *pcondPtr, - PMutex *pmutexPtr, - struct timespec *ptime) -{ - pthread_cond_timedwait(pcondPtr, &pmutexPtr->mutex, ptime); -} -#endif /* HAVE_PTHREAD_MUTEX_RECURSIVE */ - -#ifndef TCL_NO_DEPRECATED -typedef struct { +typedef struct ThreadSpecificData { char nabuf[16]; } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; -#endif /* TCL_NO_DEPRECATED */ /* - * globalLock is used to serialize creation of mutexes, condition variables, + * masterLock is used to serialize creation of mutexes, condition variables, * and thread local storage. This is the only place that can count on the * ability to statically initialize the mutex. */ -static pthread_mutex_t globalLock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t masterLock = PTHREAD_MUTEX_INITIALIZER; /* * initLock is used to serialize initialization and finalization of Tcl. It - * cannot use any dynamically allocated storage. + * cannot use any dyamically allocated storage. */ static pthread_mutex_t initLock = PTHREAD_MUTEX_INITIALIZER; /* * allocLock is used by Tcl's version of malloc for synchronization. For - * obvious reasons, cannot use any dynamically allocated storage. + * obvious reasons, cannot use any dyamically allocated storage. */ -static PMutex allocLock; -static pthread_once_t allocLockInitOnce = PTHREAD_ONCE_INIT; +static pthread_mutex_t allocLock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t *allocLockPtr = &allocLock; -static void -allocLockInit(void) -{ - PMutexInit(&allocLock); -} -static PMutex *allocLockPtr = &allocLock; +/* + * These are for the critical sections inside this file. + */ + +#define MASTER_LOCK pthread_mutex_lock(&masterLock) +#define MASTER_UNLOCK pthread_mutex_unlock(&masterLock) #endif /* TCL_THREADS */ + /* *---------------------------------------------------------------------- @@ -220,13 +73,13 @@ static PMutex *allocLockPtr = &allocLock; int TclpThreadCreate( Tcl_ThreadId *idPtr, /* Return, the ID of the thread */ - Tcl_ThreadCreateProc *proc, /* Main() function of the thread */ - void *clientData, /* The one argument to Main() */ - TCL_HASH_TYPE stackSize, /* Size of stack for the new thread */ + Tcl_ThreadCreateProc proc, /* Main() function of the thread */ + ClientData clientData, /* The one argument to Main() */ + int stackSize, /* Size of stack for the new thread */ int flags) /* Flags controlling behaviour of the new * thread. */ { -#if TCL_THREADS +#ifdef TCL_THREADS pthread_attr_t attr; pthread_t theThread; int result; @@ -236,7 +89,7 @@ TclpThreadCreate( #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE if (stackSize != TCL_THREAD_STACK_DEFAULT) { - pthread_attr_setstacksize(&attr, (size_t)stackSize); + pthread_attr_setstacksize(&attr, (size_t) stackSize); #ifdef TCL_THREAD_STACK_MIN } else { /* @@ -252,23 +105,22 @@ TclpThreadCreate( */ size_t size; - result = pthread_attr_getstacksize(&attr, &size); if (!result && (size < TCL_THREAD_STACK_MIN)) { - pthread_attr_setstacksize(&attr, (size_t)TCL_THREAD_STACK_MIN); + pthread_attr_setstacksize(&attr, (size_t) TCL_THREAD_STACK_MIN); } -#endif /* TCL_THREAD_STACK_MIN */ +#endif } -#endif /* HAVE_PTHREAD_ATTR_SETSTACKSIZE */ - - if (!(flags & TCL_THREAD_JOINABLE)) { - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); +#endif + if (! (flags & TCL_THREAD_JOINABLE)) { + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); } + if (pthread_create(&theThread, &attr, - (void * (*)(void *))(void *)proc, (void *)clientData) && + (void * (*)(void *))proc, (void *)clientData) && pthread_create(&theThread, NULL, - (void * (*)(void *))(void *)proc, (void *)clientData)) { + (void * (*)(void *))proc, (void *)clientData)) { result = TCL_ERROR; } else { *idPtr = (Tcl_ThreadId)theThread; @@ -277,11 +129,6 @@ TclpThreadCreate( pthread_attr_destroy(&attr); return result; #else - (void)idPtr; - (void)proc; - (void)clientData; - (void)stackSize; - (void)flags; return TCL_ERROR; #endif /* TCL_THREADS */ } @@ -309,7 +156,7 @@ Tcl_JoinThread( * thread we wait upon will be written into. * May be NULL. */ { -#if TCL_THREADS +#ifdef TCL_THREADS int result; unsigned long retcode, *retcodePtr = &retcode; @@ -319,13 +166,11 @@ Tcl_JoinThread( } return (result == 0) ? TCL_OK : TCL_ERROR; #else - (void)threadId; - (void)state; - return TCL_ERROR; #endif } +#ifdef TCL_THREADS /* *---------------------------------------------------------------------- * @@ -346,12 +191,102 @@ void TclpThreadExit( int status) { -#if TCL_THREADS pthread_exit(INT2PTR(status)); -#else /* TCL_THREADS */ - exit(status); +} #endif /* TCL_THREADS */ + +#ifdef TCL_THREADS +/* + *---------------------------------------------------------------------- + * + * TclpThreadGetStackSize -- + * + * This procedure returns the size of the current thread's stack. + * + * Results: + * Stack size (in bytes?) or -1 for error or 0 for undeterminable. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +size_t +TclpThreadGetStackSize(void) +{ + size_t stackSize = 0; +#if defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) && defined(TclpPthreadGetAttrs) + pthread_attr_t threadAttr; /* This will hold the thread attributes for + * the current thread. */ +#ifdef __GLIBC__ + /* + * Fix for [Bug 1815573] + * + * DESCRIPTION: + * On linux TclpPthreadGetAttrs (which is pthread_attr_get_np) may return + * bogus values on the initial thread. + * + * ASSUMPTIONS: + * There seems to be no api to determine if we are on the initial + * thread. The simple scheme implemented here assumes: + * 1. The first Tcl interp to be created lives in the initial thread. If + * this assumption is not true, the fix is to call + * TclpThreadGetStackSize from the initial thread previous to + * creating any Tcl interpreter. In this case, especially if another + * Tcl interpreter may be created in the initial thread, it might be + * better to enable the second branch in the #if below + * 2. There will be no races in creating the first Tcl interp - ie, the + * second Tcl interp will be created only after the first call to + * Tcl_CreateInterp returns. + * + * These assumptions are satisfied by tclsh. Embedders on linux may want + * to check their validity, and possibly adapt the code on failing to meet + * them. + */ + + static int initialized = 0; + + if (!initialized) { + initialized = 1; + return 0; + } else { +#else + { +#endif + if (pthread_attr_init(&threadAttr) != 0) { + return -1; + } + if (TclpPthreadGetAttrs(pthread_self(), &threadAttr) != 0) { + pthread_attr_destroy(&threadAttr); + return (size_t)-1; + } + } + + + if (pthread_attr_getstacksize(&threadAttr, &stackSize) != 0) { + pthread_attr_destroy(&threadAttr); + return (size_t)-1; + } + pthread_attr_destroy(&threadAttr); +#elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) +#ifdef __APPLE__ + /* + * On Darwin, the API below does not return the correct stack size for the + * main thread (which is not a real pthread), so fallback to getrlimit(). + */ + if (!pthread_main_np()) +#endif + stackSize = pthread_get_stacksize_np(pthread_self()); +#else + /* + * Cannot determine the real stack size of this thread. The caller might + * want to try looking at the process accounting limits instead. + */ +#endif + return stackSize; } +#endif /* TCL_THREADS */ /* *---------------------------------------------------------------------- @@ -372,7 +307,7 @@ TclpThreadExit( Tcl_ThreadId Tcl_GetCurrentThread(void) { -#if TCL_THREADS +#ifdef TCL_THREADS return (Tcl_ThreadId) pthread_self(); #else return (Tcl_ThreadId) 0; @@ -401,7 +336,7 @@ Tcl_GetCurrentThread(void) void TclpInitLock(void) { -#if TCL_THREADS +#ifdef TCL_THREADS pthread_mutex_lock(&initLock); #endif } @@ -409,7 +344,7 @@ TclpInitLock(void) /* *---------------------------------------------------------------------- * - * TclFinalizeLock + * TclpFinalizeLock * * This procedure is used to destroy all private resources used in this * file. @@ -427,11 +362,11 @@ TclpInitLock(void) void TclFinalizeLock(void) { -#if TCL_THREADS +#ifdef TCL_THREADS /* * You do not need to destroy mutexes that were created with the * PTHREAD_MUTEX_INITIALIZER macro. These mutexes do not need any - * destruction: globalLock, allocLock, and initLock. + * destruction: masterLock, allocLock, and initLock. */ pthread_mutex_unlock(&initLock); @@ -458,7 +393,7 @@ TclFinalizeLock(void) void TclpInitUnlock(void) { -#if TCL_THREADS +#ifdef TCL_THREADS pthread_mutex_unlock(&initLock); #endif } @@ -466,36 +401,37 @@ TclpInitUnlock(void) /* *---------------------------------------------------------------------- * - * TclpGlobalLock + * TclpMasterLock * * This procedure is used to grab a lock that serializes creation and * finalization of serialization objects. This interface is only needed * in finalization; it is hidden during creation of the objects. * * This lock must be different than the initLock because the initLock is - * held during creation of synchronization objects. + * held during creation of syncronization objects. * * Results: * None. * * Side effects: - * Acquire the global mutex. + * Acquire the master mutex. * *---------------------------------------------------------------------- */ void -TclpGlobalLock(void) +TclpMasterLock(void) { -#if TCL_THREADS - pthread_mutex_lock(&globalLock); +#ifdef TCL_THREADS + pthread_mutex_lock(&masterLock); #endif } + /* *---------------------------------------------------------------------- * - * TclpGlobalUnlock + * TclpMasterUnlock * * This procedure is used to release a lock that serializes creation and * finalization of synchronization objects. @@ -504,16 +440,16 @@ TclpGlobalLock(void) * None. * * Side effects: - * Release the global mutex. + * Release the master mutex. * *---------------------------------------------------------------------- */ void -TclpGlobalUnlock(void) +TclpMasterUnlock(void) { -#if TCL_THREADS - pthread_mutex_unlock(&globalLock); +#ifdef TCL_THREADS + pthread_mutex_unlock(&masterLock); #endif } @@ -523,7 +459,7 @@ TclpGlobalUnlock(void) * Tcl_GetAllocMutex * * This procedure returns a pointer to a statically initialized mutex for - * use by the memory allocator. The allocator must use this lock, because + * use by the memory allocator. The alloctor must use this lock, because * all other locks are allocated... * * Results: @@ -539,17 +475,15 @@ TclpGlobalUnlock(void) Tcl_Mutex * Tcl_GetAllocMutex(void) { -#if TCL_THREADS - PMutex **allocLockPtrPtr = &allocLockPtr; - - pthread_once(&allocLockInitOnce, allocLockInit); +#ifdef TCL_THREADS + pthread_mutex_t **allocLockPtrPtr = &allocLockPtr; return (Tcl_Mutex *) allocLockPtrPtr; #else return NULL; #endif } -#if TCL_THREADS +#ifdef TCL_THREADS /* *---------------------------------------------------------------------- @@ -565,7 +499,7 @@ Tcl_GetAllocMutex(void) * None. * * Side effects: - * May block the current thread. The mutex is acquired when this returns. + * May block the current thread. The mutex is aquired when this returns. * Will allocate memory for a pthread_mutex_t and initialize this the * first time this Tcl_Mutex is used. * @@ -574,26 +508,26 @@ Tcl_GetAllocMutex(void) void Tcl_MutexLock( - Tcl_Mutex *mutexPtr) /* Really (PMutex **) */ + Tcl_Mutex *mutexPtr) /* Really (pthread_mutex_t **) */ { - PMutex *pmutexPtr; + pthread_mutex_t *pmutexPtr; if (*mutexPtr == NULL) { - pthread_mutex_lock(&globalLock); + MASTER_LOCK; if (*mutexPtr == NULL) { /* - * Double inside global lock check to avoid a race condition. + * Double inside master lock check to avoid a race condition. */ - pmutexPtr = (PMutex *)ckalloc(sizeof(PMutex)); - PMutexInit(pmutexPtr); - *mutexPtr = (Tcl_Mutex) pmutexPtr; + pmutexPtr = (pthread_mutex_t *)ckalloc(sizeof(pthread_mutex_t)); + pthread_mutex_init(pmutexPtr, NULL); + *mutexPtr = (Tcl_Mutex)pmutexPtr; TclRememberMutex(mutexPtr); } - pthread_mutex_unlock(&globalLock); + MASTER_UNLOCK; } - pmutexPtr = *((PMutex **) mutexPtr); - PMutexLock(pmutexPtr); + pmutexPtr = *((pthread_mutex_t **)mutexPtr); + pthread_mutex_lock(pmutexPtr); } /* @@ -615,11 +549,10 @@ Tcl_MutexLock( void Tcl_MutexUnlock( - Tcl_Mutex *mutexPtr) /* Really (PMutex **) */ + Tcl_Mutex *mutexPtr) /* Really (pthread_mutex_t **) */ { - PMutex *pmutexPtr = *(PMutex **) mutexPtr; - - PMutexUnlock(pmutexPtr); + pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **)mutexPtr; + pthread_mutex_unlock(pmutexPtr); } /* @@ -630,7 +563,7 @@ Tcl_MutexUnlock( * This procedure is invoked to clean up one mutex. This is only safe to * call at the end of time. * - * This assumes the Global Lock is held. + * This assumes the Master Lock is held. * * Results: * None. @@ -645,11 +578,10 @@ void TclpFinalizeMutex( Tcl_Mutex *mutexPtr) { - PMutex *pmutexPtr = *(PMutex **) mutexPtr; - + pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **)mutexPtr; if (pmutexPtr != NULL) { - PMutexDestroy(pmutexPtr); - ckfree(pmutexPtr); + pthread_mutex_destroy(pmutexPtr); + ckfree((char *) pmutexPtr); *mutexPtr = NULL; } } @@ -669,7 +601,7 @@ TclpFinalizeMutex( * None. * * Side effects: - * May block the current thread. The mutex is acquired when this returns. + * May block the current thread. The mutex is aquired when this returns. * Will allocate memory for a pthread_mutex_t and initialize this the * first time this Tcl_Mutex is used. * @@ -679,15 +611,15 @@ TclpFinalizeMutex( void Tcl_ConditionWait( Tcl_Condition *condPtr, /* Really (pthread_cond_t **) */ - Tcl_Mutex *mutexPtr, /* Really (PMutex **) */ - const Tcl_Time *timePtr) /* Timeout on waiting period */ + Tcl_Mutex *mutexPtr, /* Really (pthread_mutex_t **) */ + Tcl_Time *timePtr) /* Timeout on waiting period */ { pthread_cond_t *pcondPtr; - PMutex *pmutexPtr; + pthread_mutex_t *pmutexPtr; struct timespec ptime; if (*condPtr == NULL) { - pthread_mutex_lock(&globalLock); + MASTER_LOCK; /* * Double check inside mutex to avoid race, then initialize condition @@ -695,17 +627,17 @@ Tcl_ConditionWait( */ if (*condPtr == NULL) { - pcondPtr = (pthread_cond_t *)ckalloc(sizeof(pthread_cond_t)); + pcondPtr = (pthread_cond_t *) ckalloc(sizeof(pthread_cond_t)); pthread_cond_init(pcondPtr, NULL); - *condPtr = (Tcl_Condition) pcondPtr; + *condPtr = (Tcl_Condition)pcondPtr; TclRememberCondition(condPtr); } - pthread_mutex_unlock(&globalLock); + MASTER_UNLOCK; } - pmutexPtr = *((PMutex **)mutexPtr); + pmutexPtr = *((pthread_mutex_t **)mutexPtr); pcondPtr = *((pthread_cond_t **)condPtr); if (timePtr == NULL) { - PCondWait(pcondPtr, pmutexPtr); + pthread_cond_wait(pcondPtr, pmutexPtr); } else { Tcl_Time now; @@ -718,7 +650,7 @@ Tcl_ConditionWait( ptime.tv_sec = timePtr->sec + now.sec + (timePtr->usec + now.usec) / 1000000; ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000); - PCondTimedWait(pcondPtr, pmutexPtr, &ptime); + pthread_cond_timedwait(pcondPtr, pmutexPtr, &ptime); } } @@ -746,12 +678,11 @@ Tcl_ConditionNotify( Tcl_Condition *condPtr) { pthread_cond_t *pcondPtr = *((pthread_cond_t **)condPtr); - if (pcondPtr != NULL) { pthread_cond_broadcast(pcondPtr); } else { /* - * No-one has used the condition variable, so there are no waiters. + * Noone has used the condition variable, so there are no waiters. */ } } @@ -764,7 +695,7 @@ Tcl_ConditionNotify( * This procedure is invoked to clean up a condition variable. This is * only safe to call at the end of time. * - * This assumes the Global Lock is held. + * This assumes the Master Lock is held. * * Results: * None. @@ -780,10 +711,9 @@ TclpFinalizeCondition( Tcl_Condition *condPtr) { pthread_cond_t *pcondPtr = *(pthread_cond_t **)condPtr; - if (pcondPtr != NULL) { pthread_cond_destroy(pcondPtr); - ckfree(pcondPtr); + ckfree((char *) pcondPtr); *condPtr = NULL; } } @@ -810,57 +740,55 @@ TclpFinalizeCondition( *---------------------------------------------------------------------- */ -#ifndef TCL_NO_DEPRECATED Tcl_DirEntry * TclpReaddir( - TclDIR * dir) + DIR * dir) { return TclOSreaddir(dir); } -#undef TclpInetNtoa char * TclpInetNtoa( struct in_addr addr) { -#if TCL_THREADS +#ifdef TCL_THREADS ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); unsigned char *b = (unsigned char*) &addr.s_addr; - snprintf(tsdPtr->nabuf, sizeof(tsdPtr->nabuf), "%u.%u.%u.%u", b[0], b[1], b[2], b[3]); + sprintf(tsdPtr->nabuf, "%u.%u.%u.%u", b[0], b[1], b[2], b[3]); return tsdPtr->nabuf; #else return inet_ntoa(addr); #endif } -#endif /* TCL_NO_DEPRECATED */ -#if TCL_THREADS +#ifdef TCL_THREADS /* * Additions by AOL for specialized thread memory allocator. */ #ifdef USE_THREAD_ALLOC +static volatile int initialized = 0; static pthread_key_t key; -typedef struct { +typedef struct allocMutex { Tcl_Mutex tlock; - PMutex plock; -} AllocMutex; + pthread_mutex_t plock; +} allocMutex; Tcl_Mutex * TclpNewAllocMutex(void) { - AllocMutex *lockPtr; - PMutex *plockPtr; + struct allocMutex *lockPtr; + register pthread_mutex_t *plockPtr; - lockPtr = (AllocMutex *)malloc(sizeof(AllocMutex)); + lockPtr = malloc(sizeof(struct allocMutex)); if (lockPtr == NULL) { Tcl_Panic("could not allocate lock"); } plockPtr = &lockPtr->plock; lockPtr->tlock = (Tcl_Mutex) plockPtr; - PMutexInit(&lockPtr->plock); + pthread_mutex_init(&lockPtr->plock, NULL); return &lockPtr->tlock; } @@ -868,47 +796,48 @@ void TclpFreeAllocMutex( Tcl_Mutex *mutex) /* The alloc mutex to free. */ { - AllocMutex *lockPtr = (AllocMutex *)mutex; - + allocMutex* lockPtr = (allocMutex*) mutex; if (!lockPtr) { return; } - PMutexDestroy(&lockPtr->plock); + pthread_mutex_destroy(&lockPtr->plock); free(lockPtr); } void -TclpInitAllocCache(void) -{ - pthread_key_create(&key, NULL); -} - -void TclpFreeAllocCache( void *ptr) { if (ptr != NULL) { /* - * Called by TclFinalizeThreadAllocThread() during the thread - * finalization initiated from Tcl_FinalizeThread() + * Called by the pthread lib when a thread exits */ TclFreeAllocCache(ptr); pthread_setspecific(key, NULL); - } else { + } else if (initialized) { /* - * Called by TclFinalizeThreadAlloc() during the process + * Called by us in TclFinalizeThreadAlloc() during the library * finalization initiated from Tcl_Finalize() */ pthread_key_delete(key); + initialized = 0; } } void * TclpGetAllocCache(void) { + if (!initialized) { + pthread_mutex_lock(allocLockPtr); + if (!initialized) { + pthread_key_create(&key, TclpFreeAllocCache); + initialized = 1; + } + pthread_mutex_unlock(allocLockPtr); + } return pthread_getspecific(key); } @@ -919,58 +848,6 @@ TclpSetAllocCache( pthread_setspecific(key, arg); } #endif /* USE_THREAD_ALLOC */ - -void * -TclpThreadCreateKey(void) -{ - pthread_key_t *ptkeyPtr; - - ptkeyPtr = (pthread_key_t *)TclpSysAlloc(sizeof(pthread_key_t), 0); - if (NULL == ptkeyPtr) { - Tcl_Panic("unable to allocate thread key!"); - } - - if (pthread_key_create(ptkeyPtr, NULL)) { - Tcl_Panic("unable to create pthread key!"); - } - - return ptkeyPtr; -} - -void -TclpThreadDeleteKey( - void *keyPtr) -{ - pthread_key_t *ptkeyPtr = (pthread_key_t *)keyPtr; - - if (pthread_key_delete(*ptkeyPtr)) { - Tcl_Panic("unable to delete key!"); - } - - TclpSysFree(keyPtr); -} - -void -TclpThreadSetGlobalTSD( - void *tsdKeyPtr, - void *ptr) -{ - pthread_key_t *ptkeyPtr = (pthread_key_t *)tsdKeyPtr; - - if (pthread_setspecific(*ptkeyPtr, ptr)) { - Tcl_Panic("unable to set global TSD value"); - } -} - -void * -TclpThreadGetGlobalTSD( - void *tsdKeyPtr) -{ - pthread_key_t *ptkeyPtr = (pthread_key_t *)tsdKeyPtr; - - return pthread_getspecific(*ptkeyPtr); -} - #endif /* TCL_THREADS */ /* |
