summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixThrd.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tclUnixThrd.c')
-rw-r--r--unix/tclUnixThrd.c666
1 files changed, 366 insertions, 300 deletions
diff --git a/unix/tclUnixThrd.c b/unix/tclUnixThrd.c
index bbbb3f2..d34bc88 100644
--- a/unix/tclUnixThrd.c
+++ b/unix/tclUnixThrd.c
@@ -1,43 +1,44 @@
-/*
+/*
* tclUnixThrd.c --
*
* This file implements the UNIX-specific thread support.
*
* 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.
- *
- * SCCS: @(#) tclUnixThrd.c 1.18 98/02/19 14:24:12
+ * See the file "license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tclInt.h"
#ifdef TCL_THREADS
-#include "tclPort.h"
-#include "pthread.h"
+typedef struct ThreadSpecificData {
+ char nabuf[16];
+} ThreadSpecificData;
+
+static Tcl_ThreadDataKey dataKey;
/*
- * 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.
+ * 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 masterLock = PTHREAD_MUTEX_INITIALIZER;
/*
- * initLock is used to serialize initialization and finalization
- * of Tcl. It cannot use any dyamically allocated storage.
+ * initLock is used to serialize initialization and finalization of Tcl. It
+ * 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 dyamically allocated storage.
+ * allocLock is used by Tcl's version of malloc for synchronization. For
+ * obvious reasons, cannot use any dyamically allocated storage.
*/
static pthread_mutex_t allocLock = PTHREAD_MUTEX_INITIALIZER;
@@ -51,18 +52,17 @@ static pthread_mutex_t *allocLockPtr = &allocLock;
#define MASTER_UNLOCK pthread_mutex_unlock(&masterLock)
#endif /* TCL_THREADS */
-
/*
*----------------------------------------------------------------------
*
- * Tcl_CreateThread --
+ * TclpThreadCreate --
*
* This procedure creates a new thread.
*
* Results:
- * TCL_OK if the thread could be created. The thread ID is
- * returned in a parameter.
+ * TCL_OK if the thread could be created. The thread ID is returned in a
+ * parameter.
*
* Side effects:
* A new thread is created.
@@ -71,16 +71,17 @@ static pthread_mutex_t *allocLockPtr = &allocLock;
*/
int
-Tcl_CreateThread(idPtr, proc, clientData, stackSize, flags)
- Tcl_ThreadId *idPtr; /* Return, the ID 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 thread */
+TclpThreadCreate(
+ Tcl_ThreadId *idPtr, /* Return, the ID 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
+ * thread. */
{
#ifdef TCL_THREADS
pthread_attr_t attr;
+ pthread_t theThread;
int result;
pthread_attr_init(&attr);
@@ -88,14 +89,14 @@ Tcl_CreateThread(idPtr, proc, clientData, stackSize, flags)
#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 {
- /*
- * Certain systems define a thread stack size that by default is
- * too small for many operations. The user has the option of
- * defining TCL_THREAD_STACK_MIN to a value large enough to work
- * for their needs. This would look like (for 128K min stack):
+ /*
+ * Certain systems define a thread stack size that by default is too
+ * small for many operations. The user has the option of defining
+ * TCL_THREAD_STACK_MIN to a value large enough to work for their
+ * needs. This would look like (for 128K min stack):
* make MEM_DEBUG_FLAGS=-DTCL_THREAD_STACK_MIN=131072L
*
* This solution is not optimal, as we should allow the user to
@@ -103,25 +104,27 @@ Tcl_CreateThread(idPtr, proc, clientData, stackSize, flags)
* down, and that would still leave the main thread at the default.
*/
- size_t size;
+ 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
+#endif /* TCL_THREAD_STACK_MIN */
}
-#endif
+#endif /* HAVE_PTHREAD_ATTR_SETSTACKSIZE */
+
if (! (flags & TCL_THREAD_JOINABLE)) {
- pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+ pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
}
-
- if (pthread_create((pthread_t *)idPtr, &attr,
- (void * (*)())proc, (void *)clientData) &&
- pthread_create((pthread_t *)idPtr, NULL,
- (void * (*)())proc, (void *)clientData)) {
+ if (pthread_create(&theThread, &attr,
+ (void * (*)(void *))proc, (void *)clientData) &&
+ pthread_create(&theThread, NULL,
+ (void * (*)(void *))proc, (void *)clientData)) {
result = TCL_ERROR;
} else {
+ *idPtr = (Tcl_ThreadId)theThread;
result = TCL_OK;
}
pthread_attr_destroy(&attr);
@@ -142,23 +145,26 @@ Tcl_CreateThread(idPtr, proc, clientData, stackSize, flags)
* TCL_OK if the wait was successful, TCL_ERROR else.
*
* Side effects:
- * The result area is set to the exit code of the thread we
- * waited upon.
+ * The result area is set to the exit code of the thread we waited upon.
*
*----------------------------------------------------------------------
*/
int
-Tcl_JoinThread(id, state)
- Tcl_ThreadId id; /* Id of the thread to wait upon */
- int* state; /* Reference to the storage the result
- * of the thread we wait upon will be
- * written into. */
+Tcl_JoinThread(
+ Tcl_ThreadId threadId, /* Id of the thread to wait upon. */
+ int *state) /* Reference to the storage the result of the
+ * thread we wait upon will be written into.
+ * May be NULL. */
{
#ifdef TCL_THREADS
int result;
+ unsigned long retcode, *retcodePtr = &retcode;
- result = pthread_join ((pthread_t) id, (VOID**) state);
+ result = pthread_join((pthread_t) threadId, (void**) retcodePtr);
+ if (state) {
+ *state = (int) retcode;
+ }
return (result == 0) ? TCL_OK : TCL_ERROR;
#else
return TCL_ERROR;
@@ -183,10 +189,10 @@ Tcl_JoinThread(id, state)
*/
void
-TclpThreadExit(status)
- int status;
+TclpThreadExit(
+ int status)
{
- pthread_exit((VOID *)status);
+ pthread_exit(INT2PTR(status));
}
#endif /* TCL_THREADS */
@@ -207,7 +213,7 @@ TclpThreadExit(status)
*/
Tcl_ThreadId
-Tcl_GetCurrentThread()
+Tcl_GetCurrentThread(void)
{
#ifdef TCL_THREADS
return (Tcl_ThreadId) pthread_self();
@@ -215,7 +221,6 @@ Tcl_GetCurrentThread()
return (Tcl_ThreadId) 0;
#endif
}
-
/*
*----------------------------------------------------------------------
@@ -223,9 +228,9 @@ Tcl_GetCurrentThread()
* TclpInitLock
*
* This procedure is used to grab a lock that serializes initialization
- * and finalization of Tcl. On some platforms this may also initialize
- * the mutex used to serialize creation of more mutexes and thread
- * local storage keys.
+ * and finalization of Tcl. On some platforms this may also initialize
+ * the mutex used to serialize creation of more mutexes and thread local
+ * storage keys.
*
* Results:
* None.
@@ -237,21 +242,52 @@ Tcl_GetCurrentThread()
*/
void
-TclpInitLock()
+TclpInitLock(void)
{
#ifdef TCL_THREADS
pthread_mutex_lock(&initLock);
#endif
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclpFinalizeLock
+ *
+ * This procedure is used to destroy all private resources used in this
+ * file.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Destroys everything private. TclpInitLock must be held entering this
+ * function.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclFinalizeLock(void)
+{
+#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: masterLock, allocLock, and initLock.
+ */
+ pthread_mutex_unlock(&initLock);
+#endif
+}
/*
*----------------------------------------------------------------------
*
* TclpInitUnlock
*
- * This procedure is used to release a lock that serializes initialization
- * and finalization of Tcl.
+ * This procedure is used to release a lock that serializes
+ * initialization and finalization of Tcl.
*
* Results:
* None.
@@ -263,7 +299,7 @@ TclpInitLock()
*/
void
-TclpInitUnlock()
+TclpInitUnlock(void)
{
#ifdef TCL_THREADS
pthread_mutex_unlock(&initLock);
@@ -275,13 +311,12 @@ TclpInitUnlock()
*
* 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 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 syncronization objects.
+ * This lock must be different than the initLock because the initLock is
+ * held during creation of syncronization objects.
*
* Results:
* None.
@@ -293,7 +328,7 @@ TclpInitUnlock()
*/
void
-TclpMasterLock()
+TclpMasterLock(void)
{
#ifdef TCL_THREADS
pthread_mutex_lock(&masterLock);
@@ -306,8 +341,8 @@ TclpMasterLock()
*
* TclpMasterUnlock
*
- * This procedure is used to release a lock that serializes creation
- * and finalization of synchronization objects.
+ * This procedure is used to release a lock that serializes creation and
+ * finalization of synchronization objects.
*
* Results:
* None.
@@ -319,7 +354,7 @@ TclpMasterLock()
*/
void
-TclpMasterUnlock()
+TclpMasterUnlock(void)
{
#ifdef TCL_THREADS
pthread_mutex_unlock(&masterLock);
@@ -332,13 +367,13 @@ TclpMasterUnlock()
*
* Tcl_GetAllocMutex
*
- * This procedure returns a pointer to a statically initialized
- * mutex for use by the memory allocator. The alloctor must
- * use this lock, because all other locks are allocated...
+ * This procedure returns a pointer to a statically initialized mutex for
+ * use by the memory allocator. The alloctor must use this lock, because
+ * all other locks are allocated...
*
* Results:
- * A pointer to a mutex that is suitable for passing to
- * Tcl_MutexLock and Tcl_MutexUnlock.
+ * A pointer to a mutex that is suitable for passing to Tcl_MutexLock and
+ * Tcl_MutexUnlock.
*
* Side effects:
* None.
@@ -347,10 +382,11 @@ TclpMasterUnlock()
*/
Tcl_Mutex *
-Tcl_GetAllocMutex()
+Tcl_GetAllocMutex(void)
{
#ifdef TCL_THREADS
- return (Tcl_Mutex *)&allocLockPtr;
+ pthread_mutex_t **allocLockPtrPtr = &allocLockPtr;
+ return (Tcl_Mutex *) allocLockPtrPtr;
#else
return NULL;
#endif
@@ -363,35 +399,36 @@ Tcl_GetAllocMutex()
*
* Tcl_MutexLock --
*
- * This procedure is invoked to lock a mutex. This procedure
- * handles initializing the mutex, if necessary. The caller
- * can rely on the fact that Tcl_Mutex is an opaque pointer.
- * This routine will change that pointer from NULL after first use.
+ * This procedure is invoked to lock a mutex. This procedure handles
+ * initializing the mutex, if necessary. The caller can rely on the fact
+ * that Tcl_Mutex is an opaque pointer. This routine will change that
+ * pointer from NULL after first use.
*
* Results:
* None.
*
* Side effects:
- * 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.
+ * 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.
*
*----------------------------------------------------------------------
*/
void
-Tcl_MutexLock(mutexPtr)
- Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
+Tcl_MutexLock(
+ Tcl_Mutex *mutexPtr) /* Really (pthread_mutex_t **) */
{
pthread_mutex_t *pmutexPtr;
+
if (*mutexPtr == NULL) {
MASTER_LOCK;
if (*mutexPtr == NULL) {
- /*
+ /*
* Double inside master lock check to avoid a race condition.
*/
-
- pmutexPtr = (pthread_mutex_t *)ckalloc(sizeof(pthread_mutex_t));
+
+ pmutexPtr = ckalloc(sizeof(pthread_mutex_t));
pthread_mutex_init(pmutexPtr, NULL);
*mutexPtr = (Tcl_Mutex)pmutexPtr;
TclRememberMutex(mutexPtr);
@@ -401,15 +438,14 @@ Tcl_MutexLock(mutexPtr)
pmutexPtr = *((pthread_mutex_t **)mutexPtr);
pthread_mutex_lock(pmutexPtr);
}
-
/*
*----------------------------------------------------------------------
*
* Tcl_MutexUnlock --
*
- * This procedure is invoked to unlock a mutex. The mutex must
- * have been locked by Tcl_MutexLock.
+ * This procedure is invoked to unlock a mutex. The mutex must have been
+ * locked by Tcl_MutexLock.
*
* Results:
* None.
@@ -421,21 +457,21 @@ Tcl_MutexLock(mutexPtr)
*/
void
-Tcl_MutexUnlock(mutexPtr)
- Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
+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);
}
-
/*
*----------------------------------------------------------------------
*
* TclpFinalizeMutex --
*
- * This procedure is invoked to clean up one mutex. This is only
- * safe to call at the end of time.
+ * This procedure is invoked to clean up one mutex. This is only safe to
+ * call at the end of time.
*
* This assumes the Master Lock is held.
*
@@ -449,193 +485,26 @@ Tcl_MutexUnlock(mutexPtr)
*/
void
-TclpFinalizeMutex(mutexPtr)
- Tcl_Mutex *mutexPtr;
+TclpFinalizeMutex(
+ Tcl_Mutex *mutexPtr)
{
- pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **)mutexPtr;
+ pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **) mutexPtr;
+
if (pmutexPtr != NULL) {
- ckfree((char *)pmutexPtr);
+ pthread_mutex_destroy(pmutexPtr);
+ ckfree(pmutexPtr);
*mutexPtr = NULL;
}
}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpThreadDataKeyInit --
- *
- * This procedure initializes a thread specific data block key.
- * Each thread has table of pointers to thread specific data.
- * all threads agree on which table entry is used by each module.
- * this is remembered in a "data key", that is just an index into
- * this table. To allow self initialization, the interface
- * passes a pointer to this key and the first thread to use
- * the key fills in the pointer to the key. The key should be
- * a process-wide static.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Will allocate memory the first time this process calls for
- * this key. In this case it modifies its argument
- * to hold the pointer to information about the key.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclpThreadDataKeyInit(keyPtr)
- Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
- * really (pthread_key_t **) */
-{
- pthread_key_t *pkeyPtr;
-
- MASTER_LOCK;
- if (*keyPtr == NULL) {
- pkeyPtr = (pthread_key_t *)ckalloc(sizeof(pthread_key_t));
- pthread_key_create(pkeyPtr, NULL);
- *keyPtr = (Tcl_ThreadDataKey)pkeyPtr;
- TclRememberDataKey(keyPtr);
- }
- MASTER_UNLOCK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpThreadDataKeyGet --
- *
- * This procedure returns a pointer to a block of thread local storage.
- *
- * Results:
- * A thread-specific pointer to the data structure, or NULL
- * if the memory has not been assigned to this key for this thread.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-VOID *
-TclpThreadDataKeyGet(keyPtr)
- Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
- * really (pthread_key_t **) */
-{
- pthread_key_t *pkeyPtr = *(pthread_key_t **)keyPtr;
- if (pkeyPtr == NULL) {
- return NULL;
- } else {
- return (VOID *)pthread_getspecific(*pkeyPtr);
- }
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpThreadDataKeySet --
- *
- * This procedure sets the pointer to a block of thread local storage.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Sets up the thread so future calls to TclpThreadDataKeyGet with
- * this key will return the data pointer.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclpThreadDataKeySet(keyPtr, data)
- Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
- * really (pthread_key_t **) */
- VOID *data; /* Thread local storage */
-{
- pthread_key_t *pkeyPtr = *(pthread_key_t **)keyPtr;
- pthread_setspecific(*pkeyPtr, data);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpFinalizeThreadData --
- *
- * This procedure cleans up the thread-local storage. This is
- * called once for each thread.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Frees up all thread local storage.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclpFinalizeThreadData(keyPtr)
- Tcl_ThreadDataKey *keyPtr;
-{
- VOID *result;
- pthread_key_t *pkeyPtr;
-
- if (*keyPtr != NULL) {
- pkeyPtr = *(pthread_key_t **)keyPtr;
- result = (VOID *)pthread_getspecific(*pkeyPtr);
- if (result != NULL) {
- ckfree((char *)result);
- pthread_setspecific(*pkeyPtr, (void *)NULL);
- }
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpFinalizeThreadDataKey --
- *
- * This procedure is invoked to clean up one key. This is a
- * process-wide storage identifier. The thread finalization code
- * cleans up the thread local storage itself.
- *
- * This assumes the master lock is held.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The key is deallocated.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclpFinalizeThreadDataKey(keyPtr)
- Tcl_ThreadDataKey *keyPtr;
-{
- pthread_key_t *pkeyPtr;
- if (*keyPtr != NULL) {
- pkeyPtr = *(pthread_key_t **)keyPtr;
- pthread_key_delete(*pkeyPtr);
- ckfree((char *)pkeyPtr);
- *keyPtr = NULL;
- }
-}
-
/*
*----------------------------------------------------------------------
*
* Tcl_ConditionWait --
*
- * This procedure is invoked to wait on a condition variable.
- * The mutex is automically released as part of the wait, and
- * automatically grabbed when the condition is signaled.
+ * This procedure is invoked to wait on a condition variable. The mutex
+ * is automically released as part of the wait, and automatically grabbed
+ * when the condition is signaled.
*
* The mutex must be held when this procedure is called.
*
@@ -643,18 +512,18 @@ TclpFinalizeThreadDataKey(keyPtr)
* None.
*
* Side effects:
- * 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.
+ * 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.
*
*----------------------------------------------------------------------
*/
void
-Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
- Tcl_Condition *condPtr; /* Really (pthread_cond_t **) */
- Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */
- Tcl_Time *timePtr; /* Timeout on waiting period */
+Tcl_ConditionWait(
+ Tcl_Condition *condPtr, /* Really (pthread_cond_t **) */
+ Tcl_Mutex *mutexPtr, /* Really (pthread_mutex_t **) */
+ const Tcl_Time *timePtr) /* Timeout on waiting period */
{
pthread_cond_t *pcondPtr;
pthread_mutex_t *pmutexPtr;
@@ -663,15 +532,15 @@ Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
if (*condPtr == NULL) {
MASTER_LOCK;
- /*
- * Double check inside mutex to avoid race,
- * then initialize condition variable if necessary.
+ /*
+ * Double check inside mutex to avoid race, then initialize condition
+ * variable if necessary.
*/
if (*condPtr == NULL) {
- pcondPtr = (pthread_cond_t *)ckalloc(sizeof(pthread_cond_t));
+ pcondPtr = ckalloc(sizeof(pthread_cond_t));
pthread_cond_init(pcondPtr, NULL);
- *condPtr = (Tcl_Condition)pcondPtr;
+ *condPtr = (Tcl_Condition) pcondPtr;
TclRememberCondition(condPtr);
}
MASTER_UNLOCK;
@@ -681,8 +550,17 @@ Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
if (timePtr == NULL) {
pthread_cond_wait(pcondPtr, pmutexPtr);
} else {
- ptime.tv_sec = timePtr->sec + TclpGetSeconds();
- ptime.tv_nsec = 1000 * timePtr->usec;
+ Tcl_Time now;
+
+ /*
+ * Make sure to take into account the microsecond component of the
+ * current time, including possible overflow situations. [Bug #411603]
+ */
+
+ Tcl_GetTime(&now);
+ ptime.tv_sec = timePtr->sec + now.sec +
+ (timePtr->usec + now.usec) / 1000000;
+ ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000);
pthread_cond_timedwait(pcondPtr, pmutexPtr, &ptime);
}
}
@@ -694,8 +572,8 @@ Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
*
* This procedure is invoked to signal a condition variable.
*
- * The mutex must be held during this call to avoid races,
- * but this interface does not enforce that.
+ * The mutex must be held during this call to avoid races, but this
+ * interface does not enforce that.
*
* Results:
* None.
@@ -707,8 +585,8 @@ Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
*/
void
-Tcl_ConditionNotify(condPtr)
- Tcl_Condition *condPtr;
+Tcl_ConditionNotify(
+ Tcl_Condition *condPtr)
{
pthread_cond_t *pcondPtr = *((pthread_cond_t **)condPtr);
if (pcondPtr != NULL) {
@@ -719,15 +597,14 @@ Tcl_ConditionNotify(condPtr)
*/
}
}
-
/*
*----------------------------------------------------------------------
*
* TclpFinalizeCondition --
*
- * This procedure is invoked to clean up a condition variable.
- * This is only safe to call at the end of time.
+ * This procedure is invoked to clean up a condition variable. This is
+ * only safe to call at the end of time.
*
* This assumes the Master Lock is held.
*
@@ -741,18 +618,207 @@ Tcl_ConditionNotify(condPtr)
*/
void
-TclpFinalizeCondition(condPtr)
- Tcl_Condition *condPtr;
+TclpFinalizeCondition(
+ Tcl_Condition *condPtr)
{
pthread_cond_t *pcondPtr = *(pthread_cond_t **)condPtr;
+
if (pcondPtr != NULL) {
pthread_cond_destroy(pcondPtr);
- ckfree((char *)pcondPtr);
+ ckfree(pcondPtr);
*condPtr = NULL;
}
}
+#endif /* TCL_THREADS */
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclpReaddir, TclpInetNtoa --
+ *
+ * These procedures replace core C versions to be used in a threaded
+ * environment.
+ *
+ * Results:
+ * See documentation of C functions.
+ *
+ * Side effects:
+ * See documentation of C functions.
+ *
+ * Notes:
+ * TclpReaddir is no longer used by the core (see 1095909), but it
+ * appears in the internal stubs table (see #589526).
+ *
+ *----------------------------------------------------------------------
+ */
+
+Tcl_DirEntry *
+TclpReaddir(
+ DIR * dir)
+{
+ return TclOSreaddir(dir);
+}
+
+#undef TclpInetNtoa
+char *
+TclpInetNtoa(
+ struct in_addr addr)
+{
+#ifdef TCL_THREADS
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ unsigned char *b = (unsigned char*) &addr.s_addr;
+
+ sprintf(tsdPtr->nabuf, "%u.%u.%u.%u", b[0], b[1], b[2], b[3]);
+ return tsdPtr->nabuf;
+#else
+ return inet_ntoa(addr);
+#endif
+}
+
+#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 allocMutex {
+ Tcl_Mutex tlock;
+ pthread_mutex_t plock;
+} allocMutex;
-#endif /* TCL_THREADS */
+Tcl_Mutex *
+TclpNewAllocMutex(void)
+{
+ struct allocMutex *lockPtr;
+ register pthread_mutex_t *plockPtr;
+
+ lockPtr = malloc(sizeof(struct allocMutex));
+ if (lockPtr == NULL) {
+ Tcl_Panic("could not allocate lock");
+ }
+ plockPtr = &lockPtr->plock;
+ lockPtr->tlock = (Tcl_Mutex) plockPtr;
+ pthread_mutex_init(&lockPtr->plock, NULL);
+ return &lockPtr->tlock;
+}
+
+void
+TclpFreeAllocMutex(
+ Tcl_Mutex *mutex) /* The alloc mutex to free. */
+{
+ allocMutex* lockPtr = (allocMutex*) mutex;
+ if (!lockPtr) {
+ return;
+ }
+ pthread_mutex_destroy(&lockPtr->plock);
+ free(lockPtr);
+}
+void
+TclpFreeAllocCache(
+ void *ptr)
+{
+ if (ptr != NULL) {
+ /*
+ * Called by the pthread lib when a thread exits
+ */
+
+ TclFreeAllocCache(ptr);
+ pthread_setspecific(key, NULL);
+
+ } else if (initialized) {
+ /*
+ * 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);
+}
+
+void
+TclpSetAllocCache(
+ void *arg)
+{
+ 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 */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 78
+ * End:
+ */