diff options
Diffstat (limited to 'unix/tclUnixThrd.c')
-rw-r--r-- | unix/tclUnixThrd.c | 221 |
1 files changed, 133 insertions, 88 deletions
diff --git a/unix/tclUnixThrd.c b/unix/tclUnixThrd.c index 7394545..1841242 100644 --- a/unix/tclUnixThrd.c +++ b/unix/tclUnixThrd.c @@ -5,7 +5,6 @@ * * Copyright (c) 1991-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * Copyright (c) 2008 by George Peter Staplin * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -15,7 +14,7 @@ #ifdef TCL_THREADS -typedef struct { +typedef struct ThreadSpecificData { char nabuf[16]; } ThreadSpecificData; @@ -44,7 +43,15 @@ static pthread_mutex_t initLock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t allocLock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t *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 */ + /* *---------------------------------------------------------------------- @@ -66,7 +73,7 @@ static pthread_mutex_t *allocLockPtr = &allocLock; int TclpThreadCreate( Tcl_ThreadId *idPtr, /* Return, the ID of the thread */ - Tcl_ThreadCreateProc *proc, /* Main() function of the 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 @@ -98,19 +105,18 @@ 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); } -#endif /* TCL_THREAD_STACK_MIN */ +#endif } -#endif /* HAVE_PTHREAD_ATTR_SETSTACKSIZE */ - +#endif if (! (flags & TCL_THREAD_JOINABLE)) { pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); } + if (pthread_create(&theThread, &attr, (void * (*)(void *))proc, (void *)clientData) && pthread_create(&theThread, NULL, @@ -189,6 +195,99 @@ TclpThreadExit( } #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 */ + /* *---------------------------------------------------------------------- * @@ -245,7 +344,7 @@ TclpInitLock(void) /* *---------------------------------------------------------------------- * - * TclFinalizeLock + * TclpFinalizeLock * * This procedure is used to destroy all private resources used in this * file. @@ -414,18 +513,18 @@ Tcl_MutexLock( pthread_mutex_t *pmutexPtr; if (*mutexPtr == NULL) { - pthread_mutex_lock(&masterLock); + MASTER_LOCK; if (*mutexPtr == NULL) { /* * Double inside master lock check to avoid a race condition. */ - pmutexPtr = ckalloc(sizeof(pthread_mutex_t)); + pmutexPtr = (pthread_mutex_t *)ckalloc(sizeof(pthread_mutex_t)); pthread_mutex_init(pmutexPtr, NULL); *mutexPtr = (Tcl_Mutex)pmutexPtr; TclRememberMutex(mutexPtr); } - pthread_mutex_unlock(&masterLock); + MASTER_UNLOCK; } pmutexPtr = *((pthread_mutex_t **)mutexPtr); pthread_mutex_lock(pmutexPtr); @@ -452,8 +551,7 @@ void Tcl_MutexUnlock( Tcl_Mutex *mutexPtr) /* Really (pthread_mutex_t **) */ { - pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **) mutexPtr; - + pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **)mutexPtr; pthread_mutex_unlock(pmutexPtr); } @@ -480,11 +578,10 @@ void TclpFinalizeMutex( Tcl_Mutex *mutexPtr) { - pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **) mutexPtr; - + pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **)mutexPtr; if (pmutexPtr != NULL) { pthread_mutex_destroy(pmutexPtr); - ckfree(pmutexPtr); + ckfree((char *) pmutexPtr); *mutexPtr = NULL; } } @@ -515,14 +612,14 @@ void Tcl_ConditionWait( Tcl_Condition *condPtr, /* Really (pthread_cond_t **) */ Tcl_Mutex *mutexPtr, /* Really (pthread_mutex_t **) */ - const Tcl_Time *timePtr) /* Timeout on waiting period */ + Tcl_Time *timePtr) /* Timeout on waiting period */ { pthread_cond_t *pcondPtr; pthread_mutex_t *pmutexPtr; struct timespec ptime; if (*condPtr == NULL) { - pthread_mutex_lock(&masterLock); + MASTER_LOCK; /* * Double check inside mutex to avoid race, then initialize condition @@ -530,12 +627,12 @@ Tcl_ConditionWait( */ if (*condPtr == NULL) { - pcondPtr = 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(&masterLock); + MASTER_UNLOCK; } pmutexPtr = *((pthread_mutex_t **)mutexPtr); pcondPtr = *((pthread_cond_t **)condPtr); @@ -614,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; } } @@ -651,7 +747,6 @@ TclpReaddir( return TclOSreaddir(dir); } -#undef TclpInetNtoa char * TclpInetNtoa( struct in_addr addr) @@ -673,9 +768,10 @@ TclpInetNtoa( */ #ifdef USE_THREAD_ALLOC +static volatile int initialized = 0; static pthread_key_t key; -typedef struct { +typedef struct allocMutex { Tcl_Mutex tlock; pthread_mutex_t plock; } allocMutex; @@ -683,10 +779,10 @@ typedef struct { Tcl_Mutex * TclpNewAllocMutex(void) { - allocMutex *lockPtr; + struct allocMutex *lockPtr; register pthread_mutex_t *plockPtr; - lockPtr = malloc(sizeof(allocMutex)); + lockPtr = malloc(sizeof(struct allocMutex)); if (lockPtr == NULL) { Tcl_Panic("could not allocate lock"); } @@ -709,14 +805,6 @@ TclpFreeAllocMutex( } void -TclpInitAllocCache(void) -{ - pthread_mutex_lock(allocLockPtr); - pthread_key_create(&key, NULL); - pthread_mutex_unlock(allocLockPtr); -} - -void TclpFreeAllocCache( void *ptr) { @@ -729,19 +817,28 @@ TclpFreeAllocCache( TclFreeAllocCache(ptr); pthread_setspecific(key, NULL); - } else { + } else if (initialized) { /* * Called by TclFinalizeThreadAlloc() during the process * 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, NULL); + initialized = 1; + } + pthread_mutex_unlock(allocLockPtr); + } return pthread_getspecific(key); } @@ -752,58 +849,6 @@ TclpSetAllocCache( pthread_setspecific(key, arg); } #endif /* USE_THREAD_ALLOC */ - -void * -TclpThreadCreateKey(void) -{ - pthread_key_t *ptkeyPtr; - - ptkeyPtr = TclpSysAlloc(sizeof *ptkeyPtr, 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 = keyPtr; - - if (pthread_key_delete(*ptkeyPtr)) { - Tcl_Panic("unable to delete key!"); - } - - TclpSysFree(keyPtr); -} - -void -TclpThreadSetMasterTSD( - void *tsdKeyPtr, - void *ptr) -{ - pthread_key_t *ptkeyPtr = tsdKeyPtr; - - if (pthread_setspecific(*ptkeyPtr, ptr)) { - Tcl_Panic("unable to set master TSD value"); - } -} - -void * -TclpThreadGetMasterTSD( - void *tsdKeyPtr) -{ - pthread_key_t *ptkeyPtr = tsdKeyPtr; - - return pthread_getspecific(*ptkeyPtr); -} - #endif /* TCL_THREADS */ /* |