diff options
author | Joe Mistachkin <joe@mistachkin.com> | 2013-10-28 23:39:40 (GMT) |
---|---|---|
committer | Joe Mistachkin <joe@mistachkin.com> | 2013-10-28 23:39:40 (GMT) |
commit | 6c8ec5a8fe406cf53341424e1529c9b0794b03ee (patch) | |
tree | beb6424449783d7a9c84509ad47109c9e988e1fc | |
parent | 275aef21ecc230467a7849b792c43881b58557ff (diff) | |
download | tcl-6c8ec5a8fe406cf53341424e1529c9b0794b03ee.zip tcl-6c8ec5a8fe406cf53341424e1529c9b0794b03ee.tar.gz tcl-6c8ec5a8fe406cf53341424e1529c9b0794b03ee.tar.bz2 |
Add experimental new Tcl API Tcl_UnsetThreadData.
-rw-r--r-- | doc/Thread.3 | 16 | ||||
-rw-r--r-- | generic/tcl.decls | 3 | ||||
-rw-r--r-- | generic/tclDecls.h | 14 | ||||
-rw-r--r-- | generic/tclInt.h | 12 | ||||
-rw-r--r-- | generic/tclStubInit.c | 2 | ||||
-rw-r--r-- | generic/tclThread.c | 64 | ||||
-rw-r--r-- | generic/tclThreadStorage.c | 90 | ||||
-rw-r--r-- | unix/tclUnixNotfy.c | 4 |
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; /* |