summaryrefslogtreecommitdiffstats
path: root/generic/tclThread.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclThread.c')
-rw-r--r--generic/tclThread.c390
1 files changed, 173 insertions, 217 deletions
diff --git a/generic/tclThread.c b/generic/tclThread.c
index 5ddbb91..8c972a8 100644
--- a/generic/tclThread.c
+++ b/generic/tclThread.c
@@ -1,24 +1,22 @@
-/*
+/*
* tclThread.c --
*
- * This file implements Platform independent thread operations.
- * Most of the real work is done in the platform dependent files.
+ * This file implements Platform independent thread operations. Most of
+ * the real work is done in the platform dependent files.
*
* Copyright (c) 1998 by 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.
- *
- * RCS: @(#) $Id: tclThread.c,v 1.6 2002/12/10 00:34:15 hobbs Exp $
+ * See the file "license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tclInt.h"
/*
- * There are three classes of synchronization objects:
- * mutexes, thread data keys, and condition variables.
- * The following are used to record the memory used for these
- * objects so they can be finalized.
+ * There are three classes of synchronization objects: mutexes, thread data
+ * keys, and condition variables. The following are used to record the memory
+ * used for these objects so they can be finalized.
*
* These statics are guarded by the mutex in the caller of
* TclRememberThreadData, e.g., TclpThreadDataKeyInit
@@ -27,27 +25,27 @@
typedef struct {
int num; /* Number of objects remembered */
int max; /* Max size of the array */
- char **list; /* List of pointers */
+ void **list; /* List of pointers */
} SyncObjRecord;
-static SyncObjRecord keyRecord;
-static SyncObjRecord mutexRecord;
-static SyncObjRecord condRecord;
+static SyncObjRecord keyRecord = {0, 0, NULL};
+static SyncObjRecord mutexRecord = {0, 0, NULL};
+static SyncObjRecord condRecord = {0, 0, NULL};
/*
- * Prototypes of functions used only in this file
+ * Prototypes of functions used only in this file.
*/
-
-static void RememberSyncObject _ANSI_ARGS_((char *objPtr,
- SyncObjRecord *recPtr));
-static void ForgetSyncObject _ANSI_ARGS_((char *objPtr,
- SyncObjRecord *recPtr));
-/*
+static void ForgetSyncObject(void *objPtr, SyncObjRecord *recPtr);
+static void RememberSyncObject(void *objPtr,
+ SyncObjRecord *recPtr);
+
+/*
* Several functions are #defined to nothing in tcl.h if TCL_THREADS is not
- * specified. Here we undo that so the procedures are defined in the
- * stubs table.
+ * specified. Here we undo that so the functions are defined in the stubs
+ * table.
*/
+
#ifndef TCL_THREADS
#undef Tcl_MutexLock
#undef Tcl_MutexUnlock
@@ -56,61 +54,53 @@ static void ForgetSyncObject _ANSI_ARGS_((char *objPtr,
#undef Tcl_ConditionWait
#undef Tcl_ConditionFinalize
#endif
-
/*
*----------------------------------------------------------------------
*
* Tcl_GetThreadData --
*
- * This procedure allocates and initializes a chunk of thread
- * local storage.
+ * This function allocates and initializes a chunk of thread local
+ * storage.
*
* Results:
* A thread-specific pointer to the data structure.
*
* Side effects:
- * Will allocate memory the first time this thread calls for
- * this chunk of storage.
+ * Will allocate memory the first time this thread calls for this chunk
+ * of storage.
*
*----------------------------------------------------------------------
*/
-VOID *
-Tcl_GetThreadData(keyPtr, size)
- Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk */
- int size; /* Size of storage block */
+void *
+Tcl_GetThreadData(
+ Tcl_ThreadDataKey *keyPtr, /* Identifier for the data chunk */
+ int size) /* Size of storage block */
{
- VOID *result;
+ void *result;
#ifdef TCL_THREADS
-
- /*
- * See if this is the first thread to init this key.
- */
-
- if (*keyPtr == NULL) {
- TclpThreadDataKeyInit(keyPtr);
- }
-
/*
* Initialize the key for this thread.
*/
- result = TclpThreadDataKeyGet(keyPtr);
+ result = TclThreadStorageKeyGet(keyPtr);
+
if (result == NULL) {
- result = (VOID *)ckalloc((size_t)size);
- memset(result, 0, (size_t)size);
- TclpThreadDataKeySet(keyPtr, result);
+ result = ckalloc(size);
+ memset(result, 0, (size_t) size);
+ TclThreadStorageKeySet(keyPtr, result);
}
-#else
+#else /* TCL_THREADS */
if (*keyPtr == NULL) {
- result = (VOID *)ckalloc((size_t)size);
- memset((char *)result, 0, (size_t)size);
- *keyPtr = (Tcl_ThreadDataKey)result;
- TclRememberDataKey(keyPtr);
+ result = ckalloc(size);
+ memset(result, 0, (size_t)size);
+ *keyPtr = result;
+ RememberSyncObject(keyPtr, &keyRecord);
+ } else {
+ result = *keyPtr;
}
- result = *(VOID **)keyPtr;
-#endif
+#endif /* TCL_THREADS */
return result;
}
@@ -119,11 +109,11 @@ Tcl_GetThreadData(keyPtr, size)
*
* TclThreadDataKeyGet --
*
- * This procedure returns a pointer to a block of thread local storage.
+ * This function 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.
+ * 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.
@@ -131,61 +121,27 @@ Tcl_GetThreadData(keyPtr, size)
*----------------------------------------------------------------------
*/
-VOID *
-TclThreadDataKeyGet(keyPtr)
- Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
- * really (pthread_key_t **) */
-{
-#ifdef TCL_THREADS
- return (VOID *)TclpThreadDataKeyGet(keyPtr);
-#else
- char *result = *(char **)keyPtr;
- return (VOID *)result;
-#endif /* TCL_THREADS */
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * TclThreadDataKeySet --
- *
- * This procedure sets a thread local storage pointer.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The assigned value will be returned by TclpThreadDataKeyGet.
- *
- *----------------------------------------------------------------------
- */
+void *
+TclThreadDataKeyGet(
+ Tcl_ThreadDataKey *keyPtr) /* Identifier for the data chunk. */
-void
-TclThreadDataKeySet(keyPtr, data)
- Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
- * really (pthread_key_t **) */
- VOID *data; /* Thread local storage */
{
#ifdef TCL_THREADS
- if (*keyPtr == NULL) {
- TclpThreadDataKeyInit(keyPtr);
- }
- TclpThreadDataKeySet(keyPtr, data);
-#else
- *keyPtr = (Tcl_ThreadDataKey)data;
+ return TclThreadStorageKeyGet(keyPtr);
+#else /* TCL_THREADS */
+ return *keyPtr;
#endif /* TCL_THREADS */
}
-
-
/*
*----------------------------------------------------------------------
*
* RememberSyncObject
*
- * Keep a list of (mutexes/condition variable/data key)
- * used during finalization.
+ * Keep a list of (mutexes/condition variable/data key) used during
+ * finalization.
+ *
+ * Assume master lock is held.
*
* Results:
* None.
@@ -197,33 +153,45 @@ TclThreadDataKeySet(keyPtr, data)
*/
static void
-RememberSyncObject(objPtr, recPtr)
- char *objPtr; /* Pointer to sync object */
- SyncObjRecord *recPtr; /* Record of sync objects */
+RememberSyncObject(
+ void *objPtr, /* Pointer to sync object */
+ SyncObjRecord *recPtr) /* Record of sync objects */
{
- char **newList;
+ void **newList;
int i, j;
+
+ /*
+ * Reuse any free slot in the list.
+ */
+
+ for (i=0 ; i < recPtr->num ; ++i) {
+ if (recPtr->list[i] == NULL) {
+ recPtr->list[i] = objPtr;
+ return;
+ }
+ }
+
/*
- * Save the pointer to the allocated object so it can be finalized.
* Grow the list of pointers if necessary, copying only non-NULL
* pointers to the new list.
*/
if (recPtr->num >= recPtr->max) {
recPtr->max += 8;
- newList = (char **)ckalloc(recPtr->max * sizeof(char *));
+ newList = ckalloc(recPtr->max * sizeof(void *));
for (i=0,j=0 ; i<recPtr->num ; i++) {
- if (recPtr->list[i] != NULL) {
+ if (recPtr->list[i] != NULL) {
newList[j++] = recPtr->list[i];
- }
+ }
}
if (recPtr->list != NULL) {
- ckfree((char *)recPtr->list);
+ ckfree(recPtr->list);
}
recPtr->list = newList;
recPtr->num = j;
}
+
recPtr->list[recPtr->num] = objPtr;
recPtr->num++;
}
@@ -233,7 +201,8 @@ RememberSyncObject(objPtr, recPtr)
*
* ForgetSyncObject
*
- * Remove a single object from the list.
+ * Remove a single object from the list.
+ * Assume master lock is held.
*
* Results:
* None.
@@ -245,9 +214,9 @@ RememberSyncObject(objPtr, recPtr)
*/
static void
-ForgetSyncObject(objPtr, recPtr)
- char *objPtr; /* Pointer to sync object */
- SyncObjRecord *recPtr; /* Record of sync objects */
+ForgetSyncObject(
+ void *objPtr, /* Pointer to sync object */
+ SyncObjRecord *recPtr) /* Record of sync objects */
{
int i;
@@ -264,7 +233,8 @@ ForgetSyncObject(objPtr, recPtr)
*
* TclRememberMutex
*
- * Keep a list of mutexes used during finalization.
+ * Keep a list of mutexes used during finalization.
+ * Assume master lock is held.
*
* Results:
* None.
@@ -276,19 +246,19 @@ ForgetSyncObject(objPtr, recPtr)
*/
void
-TclRememberMutex(mutexPtr)
- Tcl_Mutex *mutexPtr;
+TclRememberMutex(
+ Tcl_Mutex *mutexPtr)
{
- RememberSyncObject((char *)mutexPtr, &mutexRecord);
+ RememberSyncObject(mutexPtr, &mutexRecord);
}
/*
*----------------------------------------------------------------------
*
- * Tcl_MutexFinalize
+ * Tcl_MutexFinalize --
*
- * Finalize a single mutex and remove it from the
- * list of remembered objects.
+ * Finalize a single mutex and remove it from the list of remembered
+ * objects.
*
* Results:
* None.
@@ -300,36 +270,15 @@ TclRememberMutex(mutexPtr)
*/
void
-Tcl_MutexFinalize(mutexPtr)
- Tcl_Mutex *mutexPtr;
+Tcl_MutexFinalize(
+ Tcl_Mutex *mutexPtr)
{
#ifdef TCL_THREADS
TclpFinalizeMutex(mutexPtr);
#endif
- ForgetSyncObject((char *)mutexPtr, &mutexRecord);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclRememberDataKey
- *
- * Keep a list of thread data keys used during finalization.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Add to the key list.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclRememberDataKey(keyPtr)
- Tcl_ThreadDataKey *keyPtr;
-{
- RememberSyncObject((char *)keyPtr, &keyRecord);
+ TclpMasterLock();
+ ForgetSyncObject(mutexPtr, &mutexRecord);
+ TclpMasterUnlock();
}
/*
@@ -337,7 +286,8 @@ TclRememberDataKey(keyPtr)
*
* TclRememberCondition
*
- * Keep a list of condition variables used during finalization.
+ * Keep a list of condition variables used during finalization.
+ * Assume master lock is held.
*
* Results:
* None.
@@ -349,19 +299,19 @@ TclRememberDataKey(keyPtr)
*/
void
-TclRememberCondition(condPtr)
- Tcl_Condition *condPtr;
+TclRememberCondition(
+ Tcl_Condition *condPtr)
{
- RememberSyncObject((char *)condPtr, &condRecord);
+ RememberSyncObject(condPtr, &condRecord);
}
/*
*----------------------------------------------------------------------
*
- * Tcl_ConditionFinalize
+ * Tcl_ConditionFinalize --
*
- * Finalize a single condition variable and remove it from the
- * list of remembered objects.
+ * Finalize a single condition variable and remove it from the list of
+ * remembered objects.
*
* Results:
* None.
@@ -373,13 +323,15 @@ TclRememberCondition(condPtr)
*/
void
-Tcl_ConditionFinalize(condPtr)
- Tcl_Condition *condPtr;
+Tcl_ConditionFinalize(
+ Tcl_Condition *condPtr)
{
#ifdef TCL_THREADS
TclpFinalizeCondition(condPtr);
#endif
- ForgetSyncObject((char *)condPtr, &condRecord);
+ TclpMasterLock();
+ ForgetSyncObject(condPtr, &condRecord);
+ TclpMasterUnlock();
}
/*
@@ -387,8 +339,9 @@ Tcl_ConditionFinalize(condPtr)
*
* TclFinalizeThreadData --
*
- * This procedure cleans up the thread-local storage. This is
- * called once for each thread.
+ * This function cleans up the thread-local storage. Secondary, it cleans
+ * thread alloc cache.
+ * This is called once for each thread before thread exits.
*
* Results:
* None.
@@ -400,24 +353,12 @@ Tcl_ConditionFinalize(condPtr)
*/
void
-TclFinalizeThreadData()
+TclFinalizeThreadData(void)
{
- int i;
- Tcl_ThreadDataKey *keyPtr;
-
- TclpMasterLock();
- for (i=0 ; i<keyRecord.num ; i++) {
- keyPtr = (Tcl_ThreadDataKey *) keyRecord.list[i];
-#ifdef TCL_THREADS
- TclpFinalizeThreadData(keyPtr);
-#else
- if (*keyPtr != NULL) {
- ckfree((char *)*keyPtr);
- *keyPtr = NULL;
- }
+ TclFinalizeThreadDataThread();
+#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
+ TclFinalizeThreadAllocThread();
#endif
- }
- TclpMasterUnlock();
}
/*
@@ -425,8 +366,8 @@ TclFinalizeThreadData()
*
* TclFinalizeSynchronization --
*
- * This procedure cleans up all synchronization objects:
- * mutexes, condition variables, and thread-local storage.
+ * This function cleans up all synchronization objects: mutexes,
+ * condition variables, and thread-local storage.
*
* Results:
* None.
@@ -438,26 +379,42 @@ TclFinalizeThreadData()
*/
void
-TclFinalizeSynchronization()
+TclFinalizeSynchronization(void)
{
-#ifdef TCL_THREADS
+ int i;
+ void *blockPtr;
Tcl_ThreadDataKey *keyPtr;
+#ifdef TCL_THREADS
Tcl_Mutex *mutexPtr;
Tcl_Condition *condPtr;
- int i;
TclpMasterLock();
- for (i=0 ; i<keyRecord.num ; i++) {
- keyPtr = (Tcl_ThreadDataKey *)keyRecord.list[i];
- TclpFinalizeThreadDataKey(keyPtr);
- }
+#endif
+
+ /*
+ * If we're running unthreaded, the TSD blocks are simply stored inside
+ * their thread data keys. Free them here.
+ */
+
if (keyRecord.list != NULL) {
- ckfree((char *)keyRecord.list);
+ for (i=0 ; i<keyRecord.num ; i++) {
+ keyPtr = (Tcl_ThreadDataKey *) keyRecord.list[i];
+ blockPtr = *keyPtr;
+ ckfree(blockPtr);
+ }
+ ckfree(keyRecord.list);
keyRecord.list = NULL;
}
keyRecord.max = 0;
keyRecord.num = 0;
+#ifdef TCL_THREADS
+ /*
+ * Call thread storage master cleanup.
+ */
+
+ TclFinalizeThreadStorage();
+
for (i=0 ; i<mutexRecord.num ; i++) {
mutexPtr = (Tcl_Mutex *)mutexRecord.list[i];
if (mutexPtr != NULL) {
@@ -465,45 +422,37 @@ TclFinalizeSynchronization()
}
}
if (mutexRecord.list != NULL) {
- ckfree((char *)mutexRecord.list);
+ ckfree(mutexRecord.list);
mutexRecord.list = NULL;
}
mutexRecord.max = 0;
mutexRecord.num = 0;
for (i=0 ; i<condRecord.num ; i++) {
- condPtr = (Tcl_Condition *)condRecord.list[i];
+ condPtr = (Tcl_Condition *) condRecord.list[i];
if (condPtr != NULL) {
TclpFinalizeCondition(condPtr);
}
}
if (condRecord.list != NULL) {
- ckfree((char *)condRecord.list);
+ ckfree(condRecord.list);
condRecord.list = NULL;
}
condRecord.max = 0;
condRecord.num = 0;
TclpMasterUnlock();
-#else
- if (keyRecord.list != NULL) {
- ckfree((char *)keyRecord.list);
- keyRecord.list = NULL;
- }
- keyRecord.max = 0;
- keyRecord.num = 0;
-#endif
+#endif /* TCL_THREADS */
}
-
/*
*----------------------------------------------------------------------
*
* Tcl_ExitThread --
*
- * This procedure is called to terminate the current thread.
- * This should be used by extensions that create threads with
- * additional interpreters in them.
+ * This function is called to terminate the current thread. This should
+ * be used by extensions that create threads with additional interpreters
+ * in them.
*
* Results:
* None.
@@ -515,8 +464,8 @@ TclFinalizeSynchronization()
*/
void
-Tcl_ExitThread(status)
- int status;
+Tcl_ExitThread(
+ int status)
{
Tcl_FinalizeThread();
#ifdef TCL_THREADS
@@ -531,10 +480,9 @@ Tcl_ExitThread(status)
*
* Tcl_ConditionWait, et al. --
*
- * These noop procedures are provided so the stub table does
- * not have to be conditionalized for threads. The real
- * implementations of these functions live in the platform
- * specific files.
+ * These noop functions are provided so the stub table does not have to
+ * be conditionalized for threads. The real implementations of these
+ * functions live in the platform specific files.
*
* Results:
* None.
@@ -547,31 +495,39 @@ Tcl_ExitThread(status)
#undef Tcl_ConditionWait
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 */
{
}
#undef Tcl_ConditionNotify
void
-Tcl_ConditionNotify(condPtr)
- Tcl_Condition *condPtr;
+Tcl_ConditionNotify(
+ Tcl_Condition *condPtr)
{
}
#undef Tcl_MutexLock
void
-Tcl_MutexLock(mutexPtr)
- Tcl_Mutex *mutexPtr;
+Tcl_MutexLock(
+ Tcl_Mutex *mutexPtr)
{
}
#undef Tcl_MutexUnlock
void
-Tcl_MutexUnlock(mutexPtr)
- Tcl_Mutex *mutexPtr;
+Tcl_MutexUnlock(
+ Tcl_Mutex *mutexPtr)
{
}
-#endif
+#endif /* !TCL_THREADS */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 78
+ * End:
+ */