summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixThrd.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tclUnixThrd.c')
-rw-r--r--unix/tclUnixThrd.c533
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 */
/*