summaryrefslogtreecommitdiffstats
path: root/win/tclWinThrd.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinThrd.c')
-rw-r--r--win/tclWinThrd.c708
1 files changed, 272 insertions, 436 deletions
diff --git a/win/tclWinThrd.c b/win/tclWinThrd.c
index 13fd411..8544e71 100644
--- a/win/tclWinThrd.c
+++ b/win/tclWinThrd.c
@@ -1,4 +1,4 @@
-/*
+/*
* tclWinThread.c --
*
* This file implements the Windows-specific thread operations.
@@ -6,25 +6,23 @@
* Copyright (c) 1998 by Sun Microsystems, Inc.
* Copyright (c) 1999 by Scriptics Corporation
*
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * See the file "license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tclWinInt.h"
-#include <fcntl.h>
-#include <io.h>
#include <sys/stat.h>
/*
- * This is the master lock used to serialize access to other
- * serialization data structures.
+ * This is the master lock used to serialize access to other serialization
+ * data structures.
*/
static CRITICAL_SECTION masterLock;
static int init = 0;
-#define MASTER_LOCK TclpMasterLock()
-#define MASTER_UNLOCK TclpMasterUnlock()
+#define MASTER_LOCK TclpMasterLock()
+#define MASTER_UNLOCK TclpMasterUnlock()
/*
@@ -35,38 +33,39 @@ static int init = 0;
static CRITICAL_SECTION initLock;
/*
- * allocLock is used by Tcl's version of malloc for synchronization.
- * For obvious reasons, cannot use any dyamically allocated storage.
+ * allocLock is used by Tcl's version of malloc for synchronization. For
+ * obvious reasons, cannot use any dyamically allocated storage.
*/
#ifdef TCL_THREADS
-static CRITICAL_SECTION allocLock;
-static Tcl_Mutex allocLockPtr = (Tcl_Mutex) &allocLock;
+static struct Tcl_Mutex_ {
+ CRITICAL_SECTION crit;
+} allocLock;
+static Tcl_Mutex allocLockPtr = &allocLock;
static int allocOnce = 0;
#endif /* TCL_THREADS */
/*
* The joinLock serializes Create- and ExitThread. This is necessary to
- * prevent a race where a new joinable thread exits before the creating
- * thread had the time to create the necessary data structures in the
- * emulation layer.
+ * prevent a race where a new joinable thread exits before the creating thread
+ * had the time to create the necessary data structures in the emulation
+ * layer.
*/
static CRITICAL_SECTION joinLock;
/*
- * Condition variables are implemented with a combination of a
- * per-thread Windows Event and a per-condition waiting queue.
- * The idea is that each thread has its own Event that it waits
- * on when it is doing a ConditionWait; it uses the same event for
- * all condition variables because it only waits on one at a time.
- * Each condition variable has a queue of waiting threads, and a
- * mutex used to serialize access to this queue.
- *
- * Special thanks to David Nichols and
- * Jim Davidson for advice on the Condition Variable implementation.
+ * Condition variables are implemented with a combination of a per-thread
+ * Windows Event and a per-condition waiting queue. The idea is that each
+ * thread has its own Event that it waits on when it is doing a ConditionWait;
+ * it uses the same event for all condition variables because it only waits on
+ * one at a time. Each condition variable has a queue of waiting threads, and
+ * a mutex used to serialize access to this queue.
+ *
+ * Special thanks to David Nichols and Jim Davidson for advice on the
+ * Condition Variable implementation.
*/
/*
@@ -86,42 +85,42 @@ static Tcl_ThreadDataKey dataKey;
#endif /* TCL_THREADS */
/*
- * Additions by AOL for specialized thread memory allocator.
- */
-
-#if defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG)
-static int once;
-static DWORD tlsKey;
-
-typedef struct allocMutex {
- Tcl_Mutex tlock;
- CRITICAL_SECTION wlock;
-} allocMutex;
-#endif
-
-/*
* State bits for the thread.
- * WIN_THREAD_UNINIT Uninitialized. Must be zero because
- * of the way ThreadSpecificData is created.
+ * WIN_THREAD_UNINIT Uninitialized. Must be zero because of the way
+ * ThreadSpecificData is created.
* WIN_THREAD_RUNNING Running, not waiting.
* WIN_THREAD_BLOCKED Waiting, or trying to wait.
- */
+ */
#define WIN_THREAD_UNINIT 0x0
#define WIN_THREAD_RUNNING 0x1
#define WIN_THREAD_BLOCKED 0x2
/*
- * The per condition queue pointers and the
- * Mutex used to serialize access to the queue.
+ * The per condition queue pointers and the Mutex used to serialize access to
+ * the queue.
*/
typedef struct WinCondition {
- CRITICAL_SECTION condLock; /* Lock to serialize queuing on the condition */
+ CRITICAL_SECTION condLock; /* Lock to serialize queuing on the
+ * condition. */
struct ThreadSpecificData *firstPtr; /* Queue pointers */
struct ThreadSpecificData *lastPtr;
} WinCondition;
+/*
+ * Additions by AOL for specialized thread memory allocator.
+ */
+
+#ifdef USE_THREAD_ALLOC
+static int once;
+static DWORD tlsKey;
+
+typedef struct allocMutex {
+ Tcl_Mutex tlock;
+ CRITICAL_SECTION wlock;
+} allocMutex;
+#endif /* USE_THREAD_ALLOC */
/*
*----------------------------------------------------------------------
@@ -131,8 +130,8 @@ typedef struct WinCondition {
* This procedure creates a new thread.
*
* Results:
- * TCL_OK if the thread could be created. The thread ID is
- * returned in a parameter.
+ * TCL_OK if the thread could be created. The thread ID is returned in a
+ * parameter.
*
* Side effects:
* A new thread is created.
@@ -141,21 +140,25 @@ typedef struct WinCondition {
*/
int
-TclpThreadCreate(idPtr, proc, clientData, stackSize, flags)
- Tcl_ThreadId *idPtr; /* Return, the ID of the thread */
- Tcl_ThreadCreateProc proc; /* Main() function of the thread */
- ClientData clientData; /* The one argument to Main() */
- int stackSize; /* Size of stack for the new thread */
- int flags; /* Flags controlling behaviour of
- * the new thread */
+TclpThreadCreate(
+ Tcl_ThreadId *idPtr, /* Return, the ID of the thread. */
+ Tcl_ThreadCreateProc proc, /* Main() function of the thread. */
+ ClientData clientData, /* The one argument to Main(). */
+ int stackSize, /* Size of stack for the new thread. */
+ int flags) /* Flags controlling behaviour of the new
+ * thread. */
{
HANDLE tHandle;
EnterCriticalSection(&joinLock);
+ *idPtr = 0; /* must initialize as Tcl_Thread is a pointer and
+ * on WIN64 sizeof void* != sizeof unsigned
+ */
+
#if defined(_MSC_VER) || defined(__MSVCRT__) || defined(__BORLANDC__)
tHandle = (HANDLE) _beginthreadex(NULL, (unsigned) stackSize, proc,
- clientData, 0, (unsigned *)idPtr);
+ clientData, 0, (unsigned *)idPtr);
#else
tHandle = CreateThread(NULL, (DWORD) stackSize,
(LPTHREAD_START_ROUTINE) proc, (LPVOID) clientData,
@@ -163,11 +166,11 @@ TclpThreadCreate(idPtr, proc, clientData, stackSize, flags)
#endif
if (tHandle == NULL) {
- LeaveCriticalSection(&joinLock);
+ LeaveCriticalSection(&joinLock);
return TCL_ERROR;
} else {
- if (flags & TCL_THREAD_JOINABLE) {
- TclRememberJoinableThread (*idPtr);
+ if (flags & TCL_THREAD_JOINABLE) {
+ TclRememberJoinableThread(*idPtr);
}
/*
@@ -199,13 +202,12 @@ TclpThreadCreate(idPtr, proc, clientData, stackSize, flags)
*/
int
-Tcl_JoinThread(threadId, result)
- Tcl_ThreadId threadId; /* Id of the thread to wait upon */
- int* result; /* Reference to the storage the result
- * of the thread we wait upon will be
- * written into. */
+Tcl_JoinThread(
+ Tcl_ThreadId threadId, /* Id of the thread to wait upon */
+ int *result) /* Reference to the storage the result of the
+ * thread we wait upon will be written into. */
{
- return TclJoinThread (threadId, result);
+ return TclJoinThread(threadId, result);
}
/*
@@ -225,11 +227,11 @@ Tcl_JoinThread(threadId, result)
*/
void
-TclpThreadExit(status)
- int status;
+TclpThreadExit(
+ int status)
{
EnterCriticalSection(&joinLock);
- TclSignalExitThread (Tcl_GetCurrentThread (), status);
+ TclSignalExitThread(Tcl_GetCurrentThread(), status);
LeaveCriticalSection(&joinLock);
#if defined(_MSC_VER) || defined(__MSVCRT__) || defined(__BORLANDC__)
@@ -256,9 +258,9 @@ TclpThreadExit(status)
*/
Tcl_ThreadId
-Tcl_GetCurrentThread()
+Tcl_GetCurrentThread(void)
{
- return (Tcl_ThreadId)GetCurrentThreadId();
+ return (Tcl_ThreadId) INT2PTR(GetCurrentThreadId());
}
/*
@@ -267,9 +269,9 @@ Tcl_GetCurrentThread()
* TclpInitLock
*
* This procedure is used to grab a lock that serializes initialization
- * and finalization of Tcl. On some platforms this may also initialize
- * the mutex used to serialize creation of more mutexes and thread
- * local storage keys.
+ * and finalization of Tcl. On some platforms this may also initialize
+ * the mutex used to serialize creation of more mutexes and thread local
+ * storage keys.
*
* Results:
* None.
@@ -281,15 +283,16 @@ Tcl_GetCurrentThread()
*/
void
-TclpInitLock()
+TclpInitLock(void)
{
if (!init) {
/*
- * There is a fundamental race here that is solved by creating
- * the first Tcl interpreter in a single threaded environment.
- * Once the interpreter has been created, it is safe to create
- * more threads that create interpreters in parallel.
+ * There is a fundamental race here that is solved by creating the
+ * first Tcl interpreter in a single threaded environment. Once the
+ * interpreter has been created, it is safe to create more threads
+ * that create interpreters in parallel.
*/
+
init = 1;
InitializeCriticalSection(&joinLock);
InitializeCriticalSection(&initLock);
@@ -303,8 +306,8 @@ TclpInitLock()
*
* TclpInitUnlock
*
- * This procedure is used to release a lock that serializes initialization
- * and finalization of Tcl.
+ * This procedure is used to release a lock that serializes
+ * initialization and finalization of Tcl.
*
* Results:
* None.
@@ -316,7 +319,7 @@ TclpInitLock()
*/
void
-TclpInitUnlock()
+TclpInitUnlock(void)
{
LeaveCriticalSection(&initLock);
}
@@ -326,11 +329,11 @@ TclpInitUnlock()
*
* TclpMasterLock
*
- * This procedure is used to grab a lock that serializes creation
- * of mutexes, condition variables, and thread local storage keys.
+ * This procedure is used to grab a lock that serializes creation of
+ * mutexes, condition variables, and thread local storage keys.
*
- * This lock must be different than the initLock because the
- * initLock is held during creation of syncronization objects.
+ * This lock must be different than the initLock because the initLock is
+ * held during creation of syncronization objects.
*
* Results:
* None.
@@ -342,15 +345,16 @@ TclpInitUnlock()
*/
void
-TclpMasterLock()
+TclpMasterLock(void)
{
if (!init) {
/*
- * There is a fundamental race here that is solved by creating
- * the first Tcl interpreter in a single threaded environment.
- * Once the interpreter has been created, it is safe to create
- * more threads that create interpreters in parallel.
+ * There is a fundamental race here that is solved by creating the
+ * first Tcl interpreter in a single threaded environment. Once the
+ * interpreter has been created, it is safe to create more threads
+ * that create interpreters in parallel.
*/
+
init = 1;
InitializeCriticalSection(&joinLock);
InitializeCriticalSection(&initLock);
@@ -364,8 +368,8 @@ TclpMasterLock()
*
* TclpMasterUnlock
*
- * This procedure is used to release a lock that serializes creation
- * and deletion of synchronization objects.
+ * This procedure is used to release a lock that serializes creation and
+ * deletion of synchronization objects.
*
* Results:
* None.
@@ -377,7 +381,7 @@ TclpMasterLock()
*/
void
-TclpMasterUnlock()
+TclpMasterUnlock(void)
{
LeaveCriticalSection(&masterLock);
}
@@ -387,13 +391,13 @@ TclpMasterUnlock()
*
* Tcl_GetAllocMutex
*
- * This procedure returns a pointer to a statically initialized
- * mutex for use by the memory allocator. The alloctor must
- * use this lock, because all other locks are allocated...
+ * This procedure returns a pointer to a statically initialized mutex for
+ * use by the memory allocator. The alloctor must use this lock, because
+ * all other locks are allocated...
*
* Results:
- * A pointer to a mutex that is suitable for passing to
- * Tcl_MutexLock and Tcl_MutexUnlock.
+ * A pointer to a mutex that is suitable for passing to Tcl_MutexLock and
+ * Tcl_MutexUnlock.
*
* Side effects:
* None.
@@ -402,11 +406,11 @@ TclpMasterUnlock()
*/
Tcl_Mutex *
-Tcl_GetAllocMutex()
+Tcl_GetAllocMutex(void)
{
#ifdef TCL_THREADS
if (!allocOnce) {
- InitializeCriticalSection(&allocLock);
+ InitializeCriticalSection(&allocLock.crit);
allocOnce = 1;
}
return &allocLockPtr;
@@ -420,74 +424,85 @@ Tcl_GetAllocMutex()
*
* TclpFinalizeLock
*
- * This procedure is used to destroy all private resources used in
- * this file.
+ * This procedure is used to destroy all private resources used in this
+ * file.
*
* Results:
* None.
*
* Side effects:
- * Destroys everything private. TclpInitLock must be held
- * entering this function.
+ * Destroys everything private. TclpInitLock must be held entering this
+ * function.
*
*----------------------------------------------------------------------
*/
void
-TclFinalizeLock ()
+TclFinalizeLock(void)
{
MASTER_LOCK;
DeleteCriticalSection(&joinLock);
- /* Destroy the critical section that we are holding! */
+
+ /*
+ * Destroy the critical section that we are holding!
+ */
+
DeleteCriticalSection(&masterLock);
init = 0;
+
#ifdef TCL_THREADS
- DeleteCriticalSection(&allocLock);
- allocOnce = 0;
+ if (allocOnce) {
+ DeleteCriticalSection(&allocLock.crit);
+ allocOnce = 0;
+ }
#endif
- /* Destroy the critical section that we are holding! */
+
+ LeaveCriticalSection(&initLock);
+
+ /*
+ * Destroy the critical section that we were holding.
+ */
+
DeleteCriticalSection(&initLock);
}
#ifdef TCL_THREADS
/* locally used prototype */
-static void FinalizeConditionEvent(ClientData data);
-
+static void FinalizeConditionEvent(ClientData data);
/*
*----------------------------------------------------------------------
*
* Tcl_MutexLock --
*
- * This procedure is invoked to lock a mutex. This is a self
- * initializing mutex that is automatically finalized during
- * Tcl_Finalize.
+ * This procedure is invoked to lock a mutex. This is a self initializing
+ * mutex that is automatically finalized during Tcl_Finalize.
*
* Results:
* None.
*
* Side effects:
- * May block the current thread. The mutex is aquired when
- * this returns.
+ * May block the current thread. The mutex is aquired when this returns.
*
*----------------------------------------------------------------------
*/
void
-Tcl_MutexLock(mutexPtr)
- Tcl_Mutex *mutexPtr; /* The lock */
+Tcl_MutexLock(
+ Tcl_Mutex *mutexPtr) /* The lock */
{
CRITICAL_SECTION *csPtr;
+
if (*mutexPtr == NULL) {
MASTER_LOCK;
- /*
+ /*
* Double inside master lock check to avoid a race.
*/
if (*mutexPtr == NULL) {
- csPtr = (CRITICAL_SECTION *)ckalloc(sizeof(CRITICAL_SECTION));
+ csPtr = (CRITICAL_SECTION *) ckalloc(sizeof(CRITICAL_SECTION));
InitializeCriticalSection(csPtr);
*mutexPtr = (Tcl_Mutex)csPtr;
TclRememberMutex(mutexPtr);
@@ -515,10 +530,11 @@ Tcl_MutexLock(mutexPtr)
*/
void
-Tcl_MutexUnlock(mutexPtr)
- Tcl_Mutex *mutexPtr; /* The lock */
+Tcl_MutexUnlock(
+ Tcl_Mutex *mutexPtr) /* The lock */
{
CRITICAL_SECTION *csPtr = *((CRITICAL_SECTION **)mutexPtr);
+
LeaveCriticalSection(csPtr);
}
@@ -527,8 +543,8 @@ Tcl_MutexUnlock(mutexPtr)
*
* TclpFinalizeMutex --
*
- * This procedure is invoked to clean up one mutex. This is only
- * safe to call at the end of time.
+ * This procedure is invoked to clean up one mutex. This is only safe to
+ * call at the end of time.
*
* Results:
* None.
@@ -540,13 +556,14 @@ Tcl_MutexUnlock(mutexPtr)
*/
void
-TclpFinalizeMutex(mutexPtr)
- Tcl_Mutex *mutexPtr;
+TclpFinalizeMutex(
+ Tcl_Mutex *mutexPtr)
{
CRITICAL_SECTION *csPtr = *(CRITICAL_SECTION **)mutexPtr;
+
if (csPtr != NULL) {
DeleteCriticalSection(csPtr);
- ckfree((char *)csPtr);
+ ckfree((char *) csPtr);
*mutexPtr = NULL;
}
}
@@ -554,210 +571,11 @@ TclpFinalizeMutex(mutexPtr)
/*
*----------------------------------------------------------------------
*
- * TclpThreadDataKeyInit --
- *
- * This procedure initializes a thread specific data block key.
- * Each thread has table of pointers to thread specific data.
- * all threads agree on which table entry is used by each module.
- * this is remembered in a "data key", that is just an index into
- * this table. To allow self initialization, the interface
- * passes a pointer to this key and the first thread to use
- * the key fills in the pointer to the key. The key should be
- * a process-wide static.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Will allocate memory the first time this process calls for
- * this key. In this case it modifies its argument
- * to hold the pointer to information about the key.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclpThreadDataKeyInit(keyPtr)
- Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
- * really (DWORD **) */
-{
- DWORD *indexPtr;
- DWORD newKey;
-
- MASTER_LOCK;
- if (*keyPtr == NULL) {
- indexPtr = (DWORD *)ckalloc(sizeof(DWORD));
- newKey = TlsAlloc();
- if (newKey != TLS_OUT_OF_INDEXES) {
- *indexPtr = newKey;
- } else {
- panic("TlsAlloc failed from TclpThreadDataKeyInit!"); /* this should be a fatal error */
- }
- *keyPtr = (Tcl_ThreadDataKey)indexPtr;
- TclRememberDataKey(keyPtr);
- }
- MASTER_UNLOCK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpThreadDataKeyGet --
- *
- * This procedure 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.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-VOID *
-TclpThreadDataKeyGet(keyPtr)
- Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
- * really (DWORD **) */
-{
- DWORD *indexPtr = *(DWORD **)keyPtr;
- LPVOID result;
- if (indexPtr == NULL) {
- return NULL;
- } else {
- result = TlsGetValue(*indexPtr);
- if ((result == NULL) && (GetLastError() != NO_ERROR)) {
- panic("TlsGetValue failed from TclpThreadDataKeyGet!");
- }
- return result;
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpThreadDataKeySet --
- *
- * This procedure sets the pointer to a block of thread local storage.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Sets up the thread so future calls to TclpThreadDataKeyGet with
- * this key will return the data pointer.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclpThreadDataKeySet(keyPtr, data)
- Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
- * really (pthread_key_t **) */
- VOID *data; /* Thread local storage */
-{
- DWORD *indexPtr = *(DWORD **)keyPtr;
- BOOL success;
- success = TlsSetValue(*indexPtr, (void *)data);
- if (!success) {
- panic("TlsSetValue failed from TclpThreadDataKeySet!");
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpFinalizeThreadData --
- *
- * This procedure cleans up the thread-local storage. This is
- * called once for each thread.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Frees up the memory.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclpFinalizeThreadData(keyPtr)
- Tcl_ThreadDataKey *keyPtr;
-{
- VOID *result;
- DWORD *indexPtr;
- BOOL success;
-
- if (*keyPtr != NULL) {
- indexPtr = *(DWORD **)keyPtr;
- result = (VOID *)TlsGetValue(*indexPtr);
- if (result != NULL) {
-#if defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG)
- if (indexPtr == &tlsKey) {
- TclpFreeAllocCache(result);
- return;
- }
-#endif
- ckfree((char *)result);
- success = TlsSetValue(*indexPtr, (void *)NULL);
- if (!success) {
- panic("TlsSetValue failed from TclpFinalizeThreadData!");
- }
- } else {
- if (GetLastError() != NO_ERROR) {
- panic("TlsGetValue failed from TclpFinalizeThreadData!");
- }
- }
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpFinalizeThreadDataKey --
- *
- * This procedure is invoked to clean up one key. This is a
- * process-wide storage identifier. The thread finalization code
- * cleans up the thread local storage itself.
- *
- * This assumes the master lock is held.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The key is deallocated.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclpFinalizeThreadDataKey(keyPtr)
- Tcl_ThreadDataKey *keyPtr;
-{
- DWORD *indexPtr;
- BOOL success;
- if (*keyPtr != NULL) {
- indexPtr = *(DWORD **)keyPtr;
- success = TlsFree(*indexPtr);
- if (!success) {
- panic("TlsFree failed from TclpFinalizeThreadDataKey!");
- }
- ckfree((char *)indexPtr);
- *keyPtr = NULL;
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
* Tcl_ConditionWait --
*
- * This procedure is invoked to wait on a condition variable.
- * The mutex is atomically released as part of the wait, and
- * automatically grabbed when the condition is signaled.
+ * This procedure is invoked to wait on a condition variable. The mutex
+ * is atomically released as part of the wait, and automatically grabbed
+ * when the condition is signaled.
*
* The mutex must be held when this procedure is called.
*
@@ -765,18 +583,18 @@ TclpFinalizeThreadDataKey(keyPtr)
* None.
*
* Side effects:
- * May block the current thread. The mutex is aquired when
- * this returns. Will allocate memory for a HANDLE
- * and initialize this the first time this Tcl_Condition is used.
+ * May block the current thread. The mutex is aquired when this returns.
+ * Will allocate memory for a HANDLE and initialize this the first time
+ * this Tcl_Condition is used.
*
*----------------------------------------------------------------------
*/
void
-Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
- Tcl_Condition *condPtr; /* Really (WinCondition **) */
- Tcl_Mutex *mutexPtr; /* Really (CRITICAL_SECTION **) */
- Tcl_Time *timePtr; /* Timeout on waiting period */
+Tcl_ConditionWait(
+ Tcl_Condition *condPtr, /* Really (WinCondition **) */
+ Tcl_Mutex *mutexPtr, /* Really (CRITICAL_SECTION **) */
+ Tcl_Time *timePtr) /* Timeout on waiting period */
{
WinCondition *winCondPtr; /* Per-condition queue head */
CRITICAL_SECTION *csPtr; /* Caller's Mutex, after casting */
@@ -786,21 +604,20 @@ Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
/*
- * Self initialize the two parts of the condition.
- * The per-condition and per-thread parts need to be
- * handled independently.
+ * Self initialize the two parts of the condition. The per-condition and
+ * per-thread parts need to be handled independently.
*/
if (tsdPtr->flags == WIN_THREAD_UNINIT) {
MASTER_LOCK;
- /*
+ /*
* Create the per-thread event and queue pointers.
*/
if (tsdPtr->flags == WIN_THREAD_UNINIT) {
tsdPtr->condEvent = CreateEvent(NULL, TRUE /* manual reset */,
- FALSE /* non signaled */, NULL);
+ FALSE /* non signaled */, NULL);
tsdPtr->nextPtr = NULL;
tsdPtr->prevPtr = NULL;
tsdPtr->flags = WIN_THREAD_RUNNING;
@@ -810,13 +627,12 @@ Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
if (doExit) {
/*
- * Create a per-thread exit handler to clean up the condEvent.
- * We must be careful to do this outside the Master Lock
- * because Tcl_CreateThreadExitHandler uses its own
- * ThreadSpecificData, and initializing that may drop
- * back into the Master Lock.
+ * Create a per-thread exit handler to clean up the condEvent. We
+ * must be careful to do this outside the Master Lock because
+ * Tcl_CreateThreadExitHandler uses its own ThreadSpecificData,
+ * and initializing that may drop back into the Master Lock.
*/
-
+
Tcl_CreateThreadExitHandler(FinalizeConditionEvent,
(ClientData) tsdPtr);
}
@@ -830,11 +646,11 @@ Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
*/
if (*condPtr == NULL) {
- winCondPtr = (WinCondition *)ckalloc(sizeof(WinCondition));
+ winCondPtr = (WinCondition *) ckalloc(sizeof(WinCondition));
InitializeCriticalSection(&winCondPtr->condLock);
winCondPtr->firstPtr = NULL;
winCondPtr->lastPtr = NULL;
- *condPtr = (Tcl_Condition)winCondPtr;
+ *condPtr = (Tcl_Condition) winCondPtr;
TclRememberCondition(condPtr);
}
MASTER_UNLOCK;
@@ -848,8 +664,8 @@ Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
}
/*
- * Queue the thread on the condition, using
- * the per-condition lock for serialization.
+ * Queue the thread on the condition, using the per-condition lock for
+ * serialization.
*/
tsdPtr->flags = WIN_THREAD_BLOCKED;
@@ -858,22 +674,22 @@ Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
tsdPtr->prevPtr = winCondPtr->lastPtr; /* A: */
winCondPtr->lastPtr = tsdPtr;
if (tsdPtr->prevPtr != NULL) {
- tsdPtr->prevPtr->nextPtr = tsdPtr;
+ tsdPtr->prevPtr->nextPtr = tsdPtr;
}
if (winCondPtr->firstPtr == NULL) {
- winCondPtr->firstPtr = tsdPtr;
+ winCondPtr->firstPtr = tsdPtr;
}
/*
* Unlock the caller's mutex and wait for the condition, or a timeout.
- * There is a minor issue here in that we don't count down the
- * timeout if we get notified, but another thread grabs the condition
- * before we do. In that race condition we'll wait again for the
- * full timeout. Timed waits are dubious anyway. Either you have
- * the locking protocol wrong and are masking a deadlock,
- * or you are using conditions to pause your thread.
+ * There is a minor issue here in that we don't count down the timeout if
+ * we get notified, but another thread grabs the condition before we do.
+ * In that race condition we'll wait again for the full timeout. Timed
+ * waits are dubious anyway. Either you have the locking protocol wrong
+ * and are masking a deadlock, or you are using conditions to pause your
+ * thread.
*/
-
+
LeaveCriticalSection(csPtr);
timeout = 0;
while (!timeout && (tsdPtr->flags & WIN_THREAD_BLOCKED)) {
@@ -886,32 +702,32 @@ Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
}
/*
- * Be careful on timeouts because the signal might arrive right around
- * the time limit and someone else could have taken us off the queue.
+ * Be careful on timeouts because the signal might arrive right around the
+ * time limit and someone else could have taken us off the queue.
*/
-
+
if (timeout) {
if (tsdPtr->flags & WIN_THREAD_RUNNING) {
timeout = 0;
} else {
/*
- * When dequeuing, we can leave the tsdPtr->nextPtr
- * and tsdPtr->prevPtr with dangling pointers because
- * they are reinitialilzed w/out reading them when the
- * thread is enqueued later.
+ * When dequeuing, we can leave the tsdPtr->nextPtr and
+ * tsdPtr->prevPtr with dangling pointers because they are
+ * reinitialilzed w/out reading them when the thread is enqueued
+ * later.
*/
- if (winCondPtr->firstPtr == tsdPtr) {
- winCondPtr->firstPtr = tsdPtr->nextPtr;
- } else {
- tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
- }
- if (winCondPtr->lastPtr == tsdPtr) {
- winCondPtr->lastPtr = tsdPtr->prevPtr;
- } else {
- tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
- }
- tsdPtr->flags = WIN_THREAD_RUNNING;
+ if (winCondPtr->firstPtr == tsdPtr) {
+ winCondPtr->firstPtr = tsdPtr->nextPtr;
+ } else {
+ tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
+ }
+ if (winCondPtr->lastPtr == tsdPtr) {
+ winCondPtr->lastPtr = tsdPtr->prevPtr;
+ } else {
+ tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
+ }
+ tsdPtr->flags = WIN_THREAD_RUNNING;
}
}
@@ -926,8 +742,8 @@ Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
*
* This procedure is invoked to signal a condition variable.
*
- * The mutex must be held during this call to avoid races,
- * but this interface does not enforce that.
+ * The mutex must be held during this call to avoid races, but this
+ * interface does not enforce that.
*
* Results:
* None.
@@ -939,13 +755,13 @@ Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
*/
void
-Tcl_ConditionNotify(condPtr)
- Tcl_Condition *condPtr;
+Tcl_ConditionNotify(
+ Tcl_Condition *condPtr)
{
WinCondition *winCondPtr;
ThreadSpecificData *tsdPtr;
- if (condPtr != NULL) {
+ if (*condPtr != NULL) {
winCondPtr = *((WinCondition **)condPtr);
if (winCondPtr == NULL) {
@@ -953,9 +769,9 @@ Tcl_ConditionNotify(condPtr)
}
/*
- * Loop through all the threads waiting on the condition
- * and notify them (i.e., broadcast semantics). The queue
- * manipulation is guarded by the per-condition coordinating mutex.
+ * Loop through all the threads waiting on the condition and notify
+ * them (i.e., broadcast semantics). The queue manipulation is guarded
+ * by the per-condition coordinating mutex.
*/
EnterCriticalSection(&winCondPtr->condLock);
@@ -973,7 +789,7 @@ Tcl_ConditionNotify(condPtr)
LeaveCriticalSection(&winCondPtr->condLock);
} else {
/*
- * Noone has used the condition variable, so there are no waiters.
+ * No-one has used the condition variable, so there are no waiters.
*/
}
}
@@ -983,9 +799,9 @@ Tcl_ConditionNotify(condPtr)
*
* FinalizeConditionEvent --
*
- * This procedure is invoked to clean up the per-thread
- * event used to implement condition waiting.
- * This is only safe to call at the end of time.
+ * This procedure is invoked to clean up the per-thread event used to
+ * implement condition waiting. This is only safe to call at the end of
+ * time.
*
* Results:
* None.
@@ -997,10 +813,11 @@ Tcl_ConditionNotify(condPtr)
*/
static void
-FinalizeConditionEvent(data)
- ClientData data;
+FinalizeConditionEvent(
+ ClientData data)
{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)data;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *) data;
+
tsdPtr->flags = WIN_THREAD_UNINIT;
CloseHandle(tsdPtr->condEvent);
}
@@ -1010,8 +827,8 @@ FinalizeConditionEvent(data)
*
* TclpFinalizeCondition --
*
- * This procedure is invoked to clean up a condition variable.
- * This is only safe to call at the end of time.
+ * This procedure is invoked to clean up a condition variable. This is
+ * only safe to call at the end of time.
*
* This assumes the Master Lock is held.
*
@@ -1025,30 +842,33 @@ FinalizeConditionEvent(data)
*/
void
-TclpFinalizeCondition(condPtr)
- Tcl_Condition *condPtr;
+TclpFinalizeCondition(
+ Tcl_Condition *condPtr)
{
WinCondition *winCondPtr = *(WinCondition **)condPtr;
/*
- * Note - this is called long after the thread-local storage is
- * reclaimed. The per-thread condition waiting event is
- * reclaimed earlier in a per-thread exit handler, which is
- * called before thread local storage is reclaimed.
+ * Note - this is called long after the thread-local storage is reclaimed.
+ * The per-thread condition waiting event is reclaimed earlier in a
+ * per-thread exit handler, which is called before thread local storage is
+ * reclaimed.
*/
if (winCondPtr != NULL) {
DeleteCriticalSection(&winCondPtr->condLock);
- ckfree((char *)winCondPtr);
+ ckfree((char *) winCondPtr);
*condPtr = NULL;
}
}
+
+
+
/*
* Additions by AOL for specialized thread memory allocator.
*/
+#ifdef USE_THREAD_ALLOC
-#if defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG)
Tcl_Mutex *
TclpNewAllocMutex(void)
{
@@ -1056,7 +876,7 @@ TclpNewAllocMutex(void)
lockPtr = malloc(sizeof(struct allocMutex));
if (lockPtr == NULL) {
- panic("could not allocate lock");
+ Tcl_Panic("could not allocate lock");
}
lockPtr->tlock = (Tcl_Mutex) &lockPtr->wlock;
InitializeCriticalSection(&lockPtr->wlock);
@@ -1064,11 +884,14 @@ TclpNewAllocMutex(void)
}
void
-TclpFreeAllocMutex(mutex)
- Tcl_Mutex *mutex; /* The alloc mutex to free. */
+TclpFreeAllocMutex(
+ Tcl_Mutex *mutex) /* The alloc mutex to free. */
{
- allocMutex* lockPtr = (allocMutex*) mutex;
- if (!lockPtr) return;
+ allocMutex *lockPtr = (allocMutex *) mutex;
+
+ if (!lockPtr) {
+ return;
+ }
DeleteCriticalSection(&lockPtr->wlock);
free(lockPtr);
}
@@ -1080,60 +903,73 @@ TclpGetAllocCache(void)
if (!once) {
/*
- * We need to make sure that TclpFreeAllocCache is called
- * on each thread that calls this, but only on threads that
- * call this.
+ * We need to make sure that TclpFreeAllocCache is called on each
+ * thread that calls this, but only on threads that call this.
*/
- tlsKey = TlsAlloc();
+
+ tlsKey = TlsAlloc();
once = 1;
if (tlsKey == TLS_OUT_OF_INDEXES) {
- panic("could not allocate thread local storage");
+ Tcl_Panic("could not allocate thread local storage");
}
}
result = TlsGetValue(tlsKey);
if ((result == NULL) && (GetLastError() != NO_ERROR)) {
- panic("TlsGetValue failed from TclpGetAllocCache!");
+ Tcl_Panic("TlsGetValue failed from TclpGetAllocCache");
}
return result;
}
void
-TclpSetAllocCache(void *ptr)
+TclpSetAllocCache(
+ void *ptr)
{
BOOL success;
success = TlsSetValue(tlsKey, ptr);
if (!success) {
- panic("TlsSetValue failed from TclpSetAllocCache!");
+ Tcl_Panic("TlsSetValue failed from TclpSetAllocCache");
}
}
void
-TclpFreeAllocCache(void *ptr)
+TclpFreeAllocCache(
+ void *ptr)
{
BOOL success;
if (ptr != NULL) {
- /*
- * Called by the pthread lib when a thread exits
- */
- TclFreeAllocCache(ptr);
- success = TlsSetValue(tlsKey, NULL);
- if (!success) {
- panic("TlsSetValue failed from TclpFreeAllocCache!");
- }
- } else if (once) {
- /*
- * Called by us in TclFinalizeThreadAlloc() during
- * the library finalization initiated from Tcl_Finalize()
- */
- success = TlsFree(tlsKey);
- if (!success) {
- Tcl_Panic("TlsFree failed from TclpFreeAllocCache!");
- }
- once = 0; /* reset for next time. */
+ /*
+ * Called by us in TclpFinalizeThreadData when a thread exits and
+ * destroys the tsd key which stores allocator caches.
+ */
+
+ TclFreeAllocCache(ptr);
+ success = TlsSetValue(tlsKey, NULL);
+ if (!success) {
+ Tcl_Panic("TlsSetValue failed from TclpFreeAllocCache");
+ }
+ } else if (once) {
+ /*
+ * Called by us in TclFinalizeThreadAlloc() during the library
+ * finalization initiated from Tcl_Finalize()
+ */
+
+ success = TlsFree(tlsKey);
+ if (!success) {
+ Tcl_Panic("TlsFree failed from TclpFreeAllocCache");
+ }
+ once = 0; /* reset for next time. */
}
-}
+}
#endif /* USE_THREAD_ALLOC */
#endif /* TCL_THREADS */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 78
+ * End:
+ */