Compare commits
8
Commits
zipfs
...
unsetThreadData
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebb646039f | ||
|
|
e175267bec | ||
|
|
65878c47af | ||
|
|
543cd3200b | ||
|
|
d75c345663 | ||
|
|
1172c3966d | ||
|
|
d0abfbe72a | ||
|
|
18aadfce45 |
+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 */
|
||||
|
||||
+11
-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)
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------
|
||||
@@ -2665,6 +2669,7 @@ MODULE_SCOPE int TclpThreadCreate(Tcl_ThreadId *idPtr,
|
||||
MODULE_SCOPE int TclpFindVariable(const char *name, int *lengthPtr);
|
||||
MODULE_SCOPE void TclpInitLibraryPath(char **valuePtr,
|
||||
int *lengthPtr, Tcl_Encoding *encodingPtr);
|
||||
MODULE_SCOPE void TclpResetLocks(void);
|
||||
MODULE_SCOPE void TclpInitLock(void);
|
||||
MODULE_SCOPE void TclpInitPlatform(void);
|
||||
MODULE_SCOPE void TclpInitUnlock(void);
|
||||
@@ -2705,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);
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
|
||||
+115
-36
@@ -127,15 +127,6 @@ static Tcl_ThreadDataKey dataKey;
|
||||
|
||||
static int notifierCount = 0;
|
||||
|
||||
/*
|
||||
* The following static stores the process ID of the initialized notifier
|
||||
* thread. If it changes, we have passed a fork and we should start a new
|
||||
* notifier thread.
|
||||
*
|
||||
* You must hold the notifierMutex lock before accessing this variable.
|
||||
*/
|
||||
static pid_t processIDInitialized = 0;
|
||||
|
||||
/*
|
||||
* The following variable points to the head of a doubly-linked list of
|
||||
* ThreadSpecificData structures for all threads that are currently waiting on
|
||||
@@ -204,9 +195,9 @@ static Tcl_ThreadId notifierThread;
|
||||
static void NotifierThreadProc(ClientData clientData);
|
||||
#if defined(HAVE_PTHREAD_ATFORK) && !defined(__APPLE__)
|
||||
static int atForkInit = 0;
|
||||
static void AtForkPrepare(void);
|
||||
static void AtForkParent(void);
|
||||
static void AtForkChild(void);
|
||||
static void AtForkPrepareProc(void);
|
||||
static void AtForkParentProc(void);
|
||||
static void AtForkChildProc(void);
|
||||
#endif /* HAVE_PTHREAD_ATFORK */
|
||||
#endif /* TCL_THREADS */
|
||||
static int FileHandlerEventProc(Tcl_Event *evPtr, int flags);
|
||||
@@ -282,14 +273,16 @@ Tcl_InitNotifier(void)
|
||||
*/
|
||||
|
||||
Tcl_MutexLock(¬ifierMutex);
|
||||
|
||||
#if defined(HAVE_PTHREAD_ATFORK) && !defined(__APPLE__)
|
||||
/*
|
||||
* Install pthread_atfork handlers to reinitialize the notifier in the
|
||||
* child of a fork.
|
||||
* Install pthread_atfork() handlers to deal with the notifier in the
|
||||
* forked child.
|
||||
*/
|
||||
|
||||
if (!atForkInit) {
|
||||
int result = pthread_atfork(AtForkPrepare, AtForkParent, AtForkChild);
|
||||
int result = pthread_atfork(AtForkPrepareProc, AtForkParentProc,
|
||||
AtForkChildProc);
|
||||
|
||||
if (result) {
|
||||
Tcl_Panic("Tcl_InitNotifier: pthread_atfork failed");
|
||||
@@ -297,23 +290,12 @@ Tcl_InitNotifier(void)
|
||||
atForkInit = 1;
|
||||
}
|
||||
#endif /* HAVE_PTHREAD_ATFORK */
|
||||
/*
|
||||
* Check if my process id changed, e.g. I was forked
|
||||
* In this case, restart the notifier thread and close the
|
||||
* pipe to the original notifier thread
|
||||
*/
|
||||
if (notifierCount > 0 && processIDInitialized != getpid()) {
|
||||
notifierCount = 0;
|
||||
processIDInitialized = 0;
|
||||
close(triggerPipe);
|
||||
triggerPipe = -1;
|
||||
}
|
||||
|
||||
if (notifierCount == 0) {
|
||||
if (TclpThreadCreate(¬ifierThread, NotifierThreadProc, NULL,
|
||||
TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE) != TCL_OK) {
|
||||
Tcl_Panic("Tcl_InitNotifier: unable to start notifier thread");
|
||||
}
|
||||
processIDInitialized = getpid();
|
||||
}
|
||||
notifierCount++;
|
||||
|
||||
@@ -1277,7 +1259,7 @@ NotifierThreadProc(
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* AtForkPrepare --
|
||||
* AtForkPrepareProc --
|
||||
*
|
||||
* Lock the notifier in preparation for a fork.
|
||||
*
|
||||
@@ -1291,14 +1273,15 @@ NotifierThreadProc(
|
||||
*/
|
||||
|
||||
static void
|
||||
AtForkPrepare(void)
|
||||
AtForkPrepareProc(void)
|
||||
{
|
||||
Tcl_MutexLock(¬ifierMutex);
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* AtForkParent --
|
||||
* AtForkParentProc --
|
||||
*
|
||||
* Unlock the notifier in the parent after a fork.
|
||||
*
|
||||
@@ -1312,16 +1295,18 @@ AtForkPrepare(void)
|
||||
*/
|
||||
|
||||
static void
|
||||
AtForkParent(void)
|
||||
AtForkParentProc(void)
|
||||
{
|
||||
Tcl_MutexUnlock(¬ifierMutex);
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* AtForkChild --
|
||||
* AtForkChildProc --
|
||||
*
|
||||
* Unlock and reinstall the notifier in the child after a fork.
|
||||
* Assumes the notifier mutex is already held. Reset the notifier
|
||||
* state and then re-initializes it for the child process.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
@@ -1333,11 +1318,105 @@ AtForkParent(void)
|
||||
*/
|
||||
|
||||
static void
|
||||
AtForkChild(void)
|
||||
AtForkChildProc(void)
|
||||
{
|
||||
notifierMutex = NULL;
|
||||
int shouldInitNotifier = (notifierCount > 0); /* Only when in use? */
|
||||
struct ThreadSpecificData *tsdPtr;
|
||||
|
||||
/*
|
||||
* Close the trigger pipe and reset it to the default value. This
|
||||
* should cause it to be re-opened when the notifier is subsequently
|
||||
* initialized. Since the trigger pipe is opened via the notifier
|
||||
* thread (which may never have started?), check it before attempting
|
||||
* to close it.
|
||||
*/
|
||||
|
||||
if (triggerPipe >= 0) {
|
||||
close(triggerPipe);
|
||||
triggerPipe = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since the notifier thread is not really running, zero out its ID.
|
||||
* This step is not strictly necessary since its value will not be
|
||||
* checked before it is re-created.
|
||||
*/
|
||||
|
||||
notifierThread = (Tcl_ThreadId)0;
|
||||
|
||||
/*
|
||||
* Reset the notifier reference count to zero (i.e. not initialized).
|
||||
* This should force the notifier initialization code to be re-run the
|
||||
* very next time Tcl_InitNotifier is called, which will be at the end
|
||||
* of this function.
|
||||
*/
|
||||
|
||||
notifierCount = 0;
|
||||
|
||||
/*
|
||||
* Finalize and reset the condition variable. This should force it to
|
||||
* be re-created during the next call to Tcl_ConditionWait().
|
||||
*/
|
||||
|
||||
Tcl_ConditionFinalize(¬ifierCV);
|
||||
notifierCV = NULL;
|
||||
Tcl_InitNotifier();
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) {
|
||||
FileHandler *filePtr;
|
||||
for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL;
|
||||
/* NO LOOP UPDATE */) {
|
||||
FileHandler *nextFilePtr = filePtr->nextPtr;
|
||||
ckfree((char *) filePtr);
|
||||
filePtr = nextFilePtr;
|
||||
}
|
||||
Tcl_ConditionFinalize(&(tsdPtr->waitCV));
|
||||
}
|
||||
waitingListPtr = NULL;
|
||||
|
||||
/*
|
||||
* Release, finalize, and reset the notifier mutex (which has been
|
||||
* held since the AtForkPrepareProc() was called via pthread_atfork()).
|
||||
* This should force it to be re-created during the next call to
|
||||
* Tcl_MutexLock().
|
||||
*/
|
||||
|
||||
Tcl_MutexUnlock(¬ifierMutex);
|
||||
Tcl_MutexFinalize(¬ifierMutex);
|
||||
notifierMutex = NULL;
|
||||
|
||||
/*
|
||||
* Next, forcibly reset all the "one time" locks used by the threading
|
||||
* 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, attempt to free thread specific data for this module, if that
|
||||
* is necessary.
|
||||
*/
|
||||
|
||||
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
|
||||
* create the notifier thread in this process. Subsequently, that new
|
||||
* thread will re-open the trigger pipe.
|
||||
*/
|
||||
|
||||
if (shouldInitNotifier) {
|
||||
Tcl_InitNotifier();
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_PTHREAD_ATFORK */
|
||||
|
||||
|
||||
@@ -314,6 +314,36 @@ Tcl_GetCurrentThread(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclpResetLocks
|
||||
*
|
||||
* This procedure is used to forcibly reset all the "one time" locks
|
||||
* used by the other platform-specific locking procedures. Currently,
|
||||
* this procedure is only called from the notifier to handle fork()
|
||||
* and must not be called from anywhere else.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
TclpResetLocks(void)
|
||||
{
|
||||
#ifdef TCL_THREADS
|
||||
pthread_mutex_t dummyLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
memcpy((void *)&masterLock, (void *)&dummyLock, sizeof(pthread_mutex_t));
|
||||
memcpy((void *)&initLock, (void *)&dummyLock, sizeof(pthread_mutex_t));
|
||||
memcpy((void *)&allocLock, (void *)&dummyLock, sizeof(pthread_mutex_t));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
|
||||
@@ -337,6 +337,29 @@ Tcl_GetCurrentThread(void)
|
||||
return (Tcl_ThreadId) INT2PTR(GetCurrentThreadId());
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclpResetLocks
|
||||
*
|
||||
* This procedure is used to forcibly reset all the "one time" locks
|
||||
* used by the other platform-specific locking procedures. Currently,
|
||||
* this procedure does nothing and should not be called.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
TclpResetLocks(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user