Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebb646039f | ||
|
|
e175267bec | ||
|
|
65878c47af |
+14
-2
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
+11
-3
@@ -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 */
|
||||
|
||||
+10
-2
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -101,6 +101,70 @@ Tcl_GetThreadData(
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
|
||||
@@ -397,6 +397,96 @@ TclpThreadDataKeySet(
|
||||
Tcl_SetHashValue(hPtr, data);
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
|
||||
+15
-9
@@ -1320,6 +1320,7 @@ AtForkParentProc(void)
|
||||
static void
|
||||
AtForkChildProc(void)
|
||||
{
|
||||
int shouldInitNotifier = (notifierCount > 0); /* Only when in use? */
|
||||
struct ThreadSpecificData *tsdPtr;
|
||||
|
||||
/*
|
||||
@@ -1341,7 +1342,7 @@ AtForkChildProc(void)
|
||||
* checked before it is re-created.
|
||||
*/
|
||||
|
||||
notifierThread = (Tcl_ThreadId) 0;
|
||||
notifierThread = (Tcl_ThreadId)0;
|
||||
|
||||
/*
|
||||
* Reset the notifier reference count to zero (i.e. not initialized).
|
||||
@@ -1363,8 +1364,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) {
|
||||
@@ -1375,6 +1375,7 @@ AtForkChildProc(void)
|
||||
ckfree((char *) filePtr);
|
||||
filePtr = nextFilePtr;
|
||||
}
|
||||
Tcl_ConditionFinalize(&(tsdPtr->waitCV));
|
||||
}
|
||||
waitingListPtr = NULL;
|
||||
|
||||
@@ -1391,18 +1392,21 @@ AtForkChildProc(void)
|
||||
|
||||
/*
|
||||
* Next, forcibly reset all the "one time" locks used by the threading
|
||||
* subsystem. This is necessary on some (all?) variants of Unix where
|
||||
* the pthread internal state does not survive a call to fork().
|
||||
* subsystem. This may be necessary on some (all?) variants of Unix
|
||||
* where the pthread internal state does not survive a call to fork().
|
||||
*/
|
||||
|
||||
TclpResetLocks();
|
||||
|
||||
/*
|
||||
* Next, abandon the thread specific data for this file. There is no
|
||||
* clean way to free it; however, it can no longer be used.
|
||||
* Next, attempt to free thread specific data for this module, if that
|
||||
* is necessary.
|
||||
*/
|
||||
|
||||
dataKey = (Tcl_ThreadDataKey) 0;
|
||||
if (dataKey != (Tcl_ThreadDataKey)0) {
|
||||
Tcl_UnsetThreadData(&dataKey, sizeof(ThreadSpecificData), 1 /*all */);
|
||||
dataKey = (Tcl_ThreadDataKey)0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Force the notifier subsystem to be initialized now. This should
|
||||
@@ -1410,7 +1414,9 @@ AtForkChildProc(void)
|
||||
* thread will re-open the trigger pipe.
|
||||
*/
|
||||
|
||||
Tcl_InitNotifier();
|
||||
if (shouldInitNotifier) {
|
||||
Tcl_InitNotifier();
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_PTHREAD_ATFORK */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user