summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoe Mistachkin <joe@mistachkin.com>2013-10-28 23:39:40 (GMT)
committerJoe Mistachkin <joe@mistachkin.com>2013-10-28 23:39:40 (GMT)
commit6c8ec5a8fe406cf53341424e1529c9b0794b03ee (patch)
treebeb6424449783d7a9c84509ad47109c9e988e1fc
parent275aef21ecc230467a7849b792c43881b58557ff (diff)
downloadtcl-6c8ec5a8fe406cf53341424e1529c9b0794b03ee.zip
tcl-6c8ec5a8fe406cf53341424e1529c9b0794b03ee.tar.gz
tcl-6c8ec5a8fe406cf53341424e1529c9b0794b03ee.tar.bz2
Add experimental new Tcl API Tcl_UnsetThreadData.
-rw-r--r--doc/Thread.316
-rw-r--r--generic/tcl.decls3
-rw-r--r--generic/tclDecls.h14
-rw-r--r--generic/tclInt.h12
-rw-r--r--generic/tclStubInit.c2
-rw-r--r--generic/tclThread.c64
-rw-r--r--generic/tclThreadStorage.c90
-rw-r--r--unix/tclUnixNotfy.c4
8 files changed, 195 insertions, 10 deletions
diff --git a/doc/Thread.3 b/doc/Thread.3
index 80d34ad..f670202 100644
--- a/doc/Thread.3
+++ b/doc/Thread.3
@@ -9,7 +9,7 @@
.TH Threads 3 "8.1" Tcl "Tcl Library Procedures"
.BS
.SH NAME
-Tcl_ConditionNotify, Tcl_ConditionWait, Tcl_ConditionFinalize, Tcl_GetThreadData, Tcl_MutexLock, Tcl_MutexUnlock, Tcl_MutexFinalize, Tcl_CreateThread, Tcl_JoinThread \- Tcl thread support
+Tcl_ConditionNotify, Tcl_ConditionWait, Tcl_ConditionFinalize, Tcl_GetThreadData, Tcl_UnsetThreadData, Tcl_MutexLock, Tcl_MutexUnlock, Tcl_MutexFinalize, Tcl_CreateThread, Tcl_JoinThread \- Tcl thread support
.SH SYNOPSIS
.nf
\fB#include <tcl.h>\fR
@@ -27,6 +27,9 @@ Void *
\fBTcl_GetThreadData\fR(\fIkeyPtr, size\fR)
.sp
void
+\fBTcl_UnsetThreadData\fR(\fIkeyPtr, size, all\fR)
+.sp
+void
\fBTcl_MutexLock\fR(\fImutexPtr\fR)
.sp
void
@@ -53,10 +56,13 @@ Note that a polling value of 0 seconds does not make much sense.
This identifies a block of thread local storage. The key should be
static and process-wide, yet each thread will end up associating
a different block of storage with this key.
-.AP int *size in
+.AP int size in
The size of the thread local storage block. This amount of data
is allocated and initialized to zero the first time each thread
calls \fBTcl_GetThreadData\fR.
+.AP int all in
+Non-zero if the thread local storage block is to be unset for all
+threads.
.AP Tcl_ThreadId *idPtr out
The referred storage will contain the id of the newly created thread as
returned by the operating system.
@@ -129,6 +135,12 @@ thread-private data. Its argument is a key that is shared by all threads
and a size for the block of storage. The storage is automatically
allocated and initialized to all zeros the first time each thread asks for it.
The storage is automatically deallocated by \fBTcl_FinalizeThread\fR.
+.PP
+The \fBTcl_UnsetThreadData\fR function is used to manually destroy
+and remove the block of thread local storage. Normally, calling this
+function is not necessary. However, if an individual thread local
+storage block needs to be manually removed, this function provides a
+means to do it.
.SS "SYNCHRONIZATION AND COMMUNICATION"
Tcl provides \fBTcl_ThreadQueueEvent\fR and \fBTcl_ThreadAlert\fR
for handling event queuing in multithreaded applications. See
diff --git a/generic/tcl.decls b/generic/tcl.decls
index 28cee54..da29a2c 100644
--- a/generic/tcl.decls
+++ b/generic/tcl.decls
@@ -2108,6 +2108,9 @@ declare 578 {
declare 579 {
void Tcl_AppendPrintfToObj(Tcl_Obj *objPtr, const char *format, ...)
}
+declare 580 {
+ void Tcl_UnsetThreadData(Tcl_ThreadDataKey *keyPtr, int size, int all)
+}
declare 630 {
void TclUnusedStubEntry(void)
}
diff --git a/generic/tclDecls.h b/generic/tclDecls.h
index 4ca9f68..ce37c52 100644
--- a/generic/tclDecls.h
+++ b/generic/tclDecls.h
@@ -3408,7 +3408,12 @@ EXTERN Tcl_Obj * Tcl_ObjPrintf(CONST char *format, ...);
EXTERN void Tcl_AppendPrintfToObj(Tcl_Obj *objPtr,
CONST char *format, ...);
#endif
-/* Slot 580 is reserved */
+#ifndef Tcl_UnsetThreadData_TCL_DECLARED
+#define Tcl_UnsetThreadData_TCL_DECLARED
+/* 580 */
+EXTERN void Tcl_UnsetThreadData(Tcl_ThreadDataKey *keyPtr,
+ int size, int all);
+#endif
/* Slot 581 is reserved */
/* Slot 582 is reserved */
/* Slot 583 is reserved */
@@ -4078,7 +4083,7 @@ typedef struct TclStubs {
int (*tcl_AppendFormatToObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, CONST char *format, int objc, Tcl_Obj *CONST objv[]); /* 577 */
Tcl_Obj * (*tcl_ObjPrintf) (CONST char *format, ...); /* 578 */
void (*tcl_AppendPrintfToObj) (Tcl_Obj *objPtr, CONST char *format, ...); /* 579 */
- VOID *reserved580;
+ void (*tcl_UnsetThreadData) (Tcl_ThreadDataKey *keyPtr, int size, int all); /* 580 */
VOID *reserved581;
VOID *reserved582;
VOID *reserved583;
@@ -6483,7 +6488,10 @@ extern TclStubs *tclStubsPtr;
#define Tcl_AppendPrintfToObj \
(tclStubsPtr->tcl_AppendPrintfToObj) /* 579 */
#endif
-/* Slot 580 is reserved */
+#ifndef Tcl_UnsetThreadData
+#define Tcl_UnsetThreadData \
+ (tclStubsPtr->tcl_UnsetThreadData) /* 580 */
+#endif
/* Slot 581 is reserved */
/* Slot 582 is reserved */
/* Slot 583 is reserved */
diff --git a/generic/tclInt.h b/generic/tclInt.h
index 9ec4a55..0918ea6 100644
--- a/generic/tclInt.h
+++ b/generic/tclInt.h
@@ -1230,13 +1230,17 @@ typedef void **TclHandle;
MODULE_SCOPE void * TclThreadDataKeyGet(Tcl_ThreadDataKey *keyPtr);
MODULE_SCOPE void TclThreadDataKeySet(Tcl_ThreadDataKey *keyPtr,
void *data);
+MODULE_SCOPE void TclThreadFreeData(void *blockPtr, int size);
/*
* This is a convenience macro used to initialize a thread local storage ptr.
*/
-#define TCL_TSD_INIT(keyPtr) \
- (ThreadSpecificData *)Tcl_GetThreadData((keyPtr), sizeof(ThreadSpecificData))
+#define TCL_TSD_INIT(keyPtr) (ThreadSpecificData *) \
+ Tcl_GetThreadData((keyPtr), sizeof(ThreadSpecificData))
+
+#define TCL_TSD_TERM(keyPtr) (ThreadSpecificData *) \
+ Tcl_UnsetThreadData((keyPtr), sizeof(ThreadSpecificData), 0)
/*
*----------------------------------------------------------------
@@ -2706,6 +2710,10 @@ MODULE_SCOPE void TclpUnloadFile(Tcl_LoadHandle loadHandle);
MODULE_SCOPE void * TclpThreadDataKeyGet(Tcl_ThreadDataKey *keyPtr);
MODULE_SCOPE void TclpThreadDataKeySet(Tcl_ThreadDataKey *keyPtr,
void *data);
+MODULE_SCOPE void TclpThreadDataKeyUnset(Tcl_ThreadDataKey *keyPtr,
+ int freeValue);
+MODULE_SCOPE void TclpThreadDataKeyUnsetAll(Tcl_ThreadDataKey *keyPtr,
+ int freeValue);
MODULE_SCOPE void TclpThreadExit(int status);
MODULE_SCOPE size_t TclpThreadGetStackSize(void);
MODULE_SCOPE void TclRememberCondition(Tcl_Condition *mutex);
diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c
index 99f3e4b..779eb94 100644
--- a/generic/tclStubInit.c
+++ b/generic/tclStubInit.c
@@ -1340,7 +1340,7 @@ TclStubs tclStubs = {
Tcl_AppendFormatToObj, /* 577 */
Tcl_ObjPrintf, /* 578 */
Tcl_AppendPrintfToObj, /* 579 */
- NULL, /* 580 */
+ Tcl_UnsetThreadData, /* 580 */
NULL, /* 581 */
NULL, /* 582 */
NULL, /* 583 */
diff --git a/generic/tclThread.c b/generic/tclThread.c
index 8384107..83c7f8c 100644
--- a/generic/tclThread.c
+++ b/generic/tclThread.c
@@ -104,6 +104,70 @@ Tcl_GetThreadData(
/*
*----------------------------------------------------------------------
*
+ * Tcl_UnsetThreadData --
+ *
+ * This function finalizes and deallocates a chunk of thread local
+ * storage.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_UnsetThreadData(
+ Tcl_ThreadDataKey *keyPtr, /* Identifier for the data chunk */
+ int size, /* Size of storage block */
+ int all) /* Unset for all threads? */
+{
+#ifdef TCL_THREADS
+ void *result = TclpThreadDataKeyGet(keyPtr);
+ if (all) {
+ TclpThreadDataKeyUnsetAll(keyPtr, 1 /* free */);
+ } else {
+ TclpThreadDataKeyUnset(keyPtr, 1 /* free */);
+ }
+#else
+ void *result = *keyPtr;
+ TclThreadFreeData(result, size);
+ ForgetSyncObject((char *) keyPtr, &keyRecord);
+#endif /* TCL_THREADS */
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclThreadFreeData --
+ *
+ * This function deallocates a chunk of thread local storage.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclThreadFreeData(
+ void *blockPtr, /* Pointer to thread local data chunk */
+ int size) /* Size of storage block */
+{
+ if (blockPtr != NULL) {
+ memset(blockPtr, 0, (size_t) size);
+ ckfree((char *) blockPtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TclThreadDataKeyGet --
*
* This function returns a pointer to a block of thread local storage.
diff --git a/generic/tclThreadStorage.c b/generic/tclThreadStorage.c
index f1df888..c9c26ef 100644
--- a/generic/tclThreadStorage.c
+++ b/generic/tclThreadStorage.c
@@ -400,6 +400,96 @@ TclpThreadDataKeySet(
/*
*----------------------------------------------------------------------
*
+ * TclpThreadDataKeyUnset --
+ *
+ * This procedure removes the pointer to a block of thread local
+ * storage.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclpThreadDataKeyUnset(
+ Tcl_ThreadDataKey *keyPtr, /* Identifier for the data chunk, really
+ * (pthread_key_t **) */
+ int freeValue) /* Also free the value? */
+{
+ Tcl_HashTable *hashTablePtr;
+ Tcl_HashEntry *hPtr;
+
+ hashTablePtr = ThreadStorageGetHashTable(Tcl_GetCurrentThread());
+ hPtr = Tcl_FindHashEntry(hashTablePtr, (char *) keyPtr);
+
+ if (hPtr != NULL) {
+ if (freeValue) {
+ void *blockPtr = Tcl_GetHashValue(hPtr);
+
+ if (blockPtr != NULL) {
+ ckfree(blockPtr);
+ }
+ }
+ Tcl_DeleteHashEntry(hPtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclpThreadDataKeyUnsetAll --
+ *
+ * This procedure removes the pointer to a block of thread local
+ * storage from all threads.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclpThreadDataKeyUnsetAll(
+ Tcl_ThreadDataKey *keyPtr, /* Identifier for the data chunk, really
+ * (pthread_key_t **) */
+ int freeValue) /* Also free the value? */
+{
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ Tcl_MutexLock(&threadStorageLock);
+ for (hPtr = Tcl_FirstHashEntry(&threadStorageHashTable, &search);
+ hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
+ Tcl_HashTable *hashTablePtr = Tcl_GetHashValue(hPtr);
+
+ if (hashTablePtr != NULL) {
+ Tcl_HashEntry *hPtr2 = Tcl_FindHashEntry(hashTablePtr,
+ (char *) keyPtr);
+
+ if (hPtr2 != NULL) {
+ if (freeValue) {
+ void *blockPtr = Tcl_GetHashValue(hPtr2);
+
+ if (blockPtr != NULL) {
+ ckfree(blockPtr);
+ }
+ }
+ Tcl_DeleteHashEntry(hPtr2);
+ }
+ }
+ }
+ Tcl_MutexUnlock(&threadStorageLock);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TclpFinalizeThreadDataThread --
*
* This procedure cleans up the thread storage hash table for the
diff --git a/unix/tclUnixNotfy.c b/unix/tclUnixNotfy.c
index 69ef7f2..96b9636 100644
--- a/unix/tclUnixNotfy.c
+++ b/unix/tclUnixNotfy.c
@@ -1363,8 +1363,7 @@ AtForkChildProc(void)
/*
* Free all the thread specific data for the notifier now. Since the
* child has no other threads, this data should be completely useless
- * at this point. Unfortunately, there is currently no clean way to
- * free the thread specific data structures themselves.
+ * at this point.
*/
for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) {
@@ -1402,6 +1401,7 @@ AtForkChildProc(void)
* clean way to free it; however, it can no longer be used.
*/
+ Tcl_UnsetThreadData(&dataKey, sizeof(ThreadSpecificData), 1 /*all */);
dataKey = (Tcl_ThreadDataKey) 0;
/*