summaryrefslogtreecommitdiffstats
path: root/generic/tclThreadJoin.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclThreadJoin.c')
-rw-r--r--generic/tclThreadJoin.c315
1 files changed, 154 insertions, 161 deletions
diff --git a/generic/tclThreadJoin.c b/generic/tclThreadJoin.c
index 4b09e1c..f3c6abd 100644
--- a/generic/tclThreadJoin.c
+++ b/generic/tclThreadJoin.c
@@ -1,66 +1,69 @@
-/*
+/*
* tclThreadJoin.c --
*
- * This file implements a platform independent emulation layer for the
- * handling of joinable threads. The Windows platform uses this code to
- * provide the functionality of joining threads. This code is currently
- * not necessary on Unix.
+ * This file implements a platform independent emulation layer for
+ * the handling of joinable threads. The Mac and Windows platforms
+ * use this code to provide the functionality of joining threads.
+ * This code is currently not necessary on Unix.
*
* Copyright (c) 2000 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 "tclInt.h"
-#ifdef WIN32
+#if defined(WIN32) || defined(MAC_TCL)
-/*
- * The information about each joinable thread is remembered in a structure as
- * defined below.
+/* The information about each joinable thread is remembered in a
+ * structure as defined below.
*/
typedef struct JoinableThread {
- Tcl_ThreadId id; /* The id of the joinable thread. */
- int result; /* A place for the result after the demise of
- * the thread. */
- int done; /* Boolean flag. Initialized to 0 and set to 1
- * after the exit of the thread. This allows a
- * thread requesting a join to detect when
- * waiting is not necessary. */
- int waitedUpon; /* Boolean flag. Initialized to 0 and set to 1
- * by the thread waiting for this one via
- * Tcl_JoinThread. Used to lock any other
- * thread trying to wait on this one. */
- Tcl_Mutex threadMutex; /* The mutex used to serialize access to this
- * structure. */
- Tcl_Condition cond; /* This is the condition a thread has to wait
- * upon to get notified of the end of the
- * described thread. It is signaled indirectly
- * by Tcl_ExitThread. */
- struct JoinableThread *nextThreadPtr;
- /* Reference to the next thread in the list of
- * joinable threads. */
+ Tcl_ThreadId id; /* The id of the joinable thread */
+ int result; /* A place for the result after the
+ * demise of the thread */
+ int done; /* Boolean flag. Initialized to 0
+ * and set to 1 after the exit of
+ * the thread. This allows a thread
+ * requesting a join to detect when
+ * waiting is not necessary. */
+ int waitedUpon; /* Boolean flag. Initialized to 0
+ * and set to 1 by the thread waiting
+ * for this one via Tcl_JoinThread.
+ * Used to lock any other thread
+ * trying to wait on this one.
+ */
+ Tcl_Mutex threadMutex; /* The mutex used to serialize access
+ * to this structure. */
+ Tcl_Condition cond; /* This is the condition a thread has
+ * to wait upon to get notified of the
+ * end of the described thread. It is
+ * signaled indirectly by
+ * Tcl_ExitThread. */
+ struct JoinableThread* nextThreadPtr; /* Reference to the next thread in the
+ * list of joinable threads */
} JoinableThread;
-/*
- * The following variable is used to maintain the global list of all joinable
- * threads. Usage by a thread is allowed only if the thread acquired the
- * 'joinMutex'.
+/* The following variable is used to maintain the global list of all
+ * joinable threads. Usage by a thread is allowed only if the
+ * thread acquired the 'joinMutex'.
*/
TCL_DECLARE_MUTEX(joinMutex)
-static JoinableThread *firstThreadPtr;
+static JoinableThread* firstThreadPtr;
+
+
/*
*----------------------------------------------------------------------
*
* TclJoinThread --
*
- * This procedure waits for the exit of the thread with the specified id
- * and returns its result.
+ * This procedure waits for the exit of the thread with the specified
+ * id and returns its result.
*
* Results:
* A standard tcl result signaling the overall success/failure of the
@@ -69,139 +72,135 @@ static JoinableThread *firstThreadPtr;
*
* Side effects:
* Deallocates the memory allocated by TclRememberJoinableThread.
- * Removes the data associated to the thread waited upon from the list of
- * joinable threads.
+ * Removes the data associated to the thread waited upon from the
+ * list of joinable threads.
*
*----------------------------------------------------------------------
*/
int
-TclJoinThread(
- Tcl_ThreadId id, /* The id of the thread to wait upon. */
- int *result) /* Reference to a location for the result of
- * the thread we are waiting upon. */
+TclJoinThread(id, result)
+ Tcl_ThreadId id; /* The id of the thread to wait upon. */
+ int* result; /* Reference to a location for the result
+ * of the thread we are waiting upon. */
{
- JoinableThread *threadPtr;
-
- /*
- * Steps done here:
+ /* Steps done here:
* i. Acquire the joinMutex and search for the thread.
* ii. Error out if it could not be found.
* iii. If found, switch from exclusive access to the list to exclusive
- * access to the thread structure.
+ * access to the thread structure.
* iv. Error out if some other is already waiting.
* v. Skip the waiting part of the thread is already done.
* vi. Wait for the thread to exit, mark it as waited upon too.
- * vii. Get the result form the structure,
+ * vii. Get the result form the structure,
* viii. switch to exclusive access of the list,
* ix. remove the structure from the list,
* x. then switch back to exclusive access to the structure
* xi. and delete it.
*/
- Tcl_MutexLock(&joinMutex);
+ JoinableThread* threadPtr;
- threadPtr = firstThreadPtr;
- while (threadPtr!=NULL && threadPtr->id!=id) {
- threadPtr = threadPtr->nextThreadPtr;
- }
+ Tcl_MutexLock (&joinMutex);
+
+ for (threadPtr = firstThreadPtr;
+ (threadPtr != (JoinableThread*) NULL) && (threadPtr->id != id);
+ threadPtr = threadPtr->nextThreadPtr)
+ /* empty body */
+ ;
- if (threadPtr == NULL) {
- /*
- * Thread not found. Either not joinable, or already waited upon and
- * exited. Whatever, an error is in order.
+ if (threadPtr == (JoinableThread*) NULL) {
+ /* Thread not found. Either not joinable, or already waited
+ * upon and exited. Whatever, an error is in order.
*/
- Tcl_MutexUnlock(&joinMutex);
- return TCL_ERROR;
+ Tcl_MutexUnlock (&joinMutex);
+ return TCL_ERROR;
}
- /*
- * [1] If we don't lock the structure before giving up exclusive access to
- * the list some other thread just completing its wait on the same thread
- * can delete the structure from under us, leaving us with a dangling
- * pointer.
+ /* [1] If we don't lock the structure before giving up exclusive access
+ * to the list some other thread just completing its wait on the same
+ * thread can delete the structure from under us, leaving us with a
+ * dangling pointer.
*/
- Tcl_MutexLock(&threadPtr->threadMutex);
- Tcl_MutexUnlock(&joinMutex);
+ Tcl_MutexLock (&threadPtr->threadMutex);
+ Tcl_MutexUnlock (&joinMutex);
- /*
- * [2] Now that we have the structure mutex any other thread that just
- * tries to delete structure will wait at location [3] until we are done
- * with the structure. And in that case we are done with it rather quickly
- * as 'waitedUpon' will be set and we will have to error out.
+ /* [2] Now that we have the structure mutex any other thread that just
+ * tries to delete structure will wait at location [3] until we are
+ * done with the structure. And in that case we are done with it
+ * rather quickly as 'waitedUpon' will be set and we will have to
+ * error out.
*/
if (threadPtr->waitedUpon) {
- Tcl_MutexUnlock(&threadPtr->threadMutex);
+ Tcl_MutexUnlock (&threadPtr->threadMutex);
return TCL_ERROR;
}
- /*
- * We are waiting now, let other threads recognize this.
+ /* We are waiting now, let other threads recognize this
*/
threadPtr->waitedUpon = 1;
while (!threadPtr->done) {
- Tcl_ConditionWait(&threadPtr->cond, &threadPtr->threadMutex, NULL);
+ Tcl_ConditionWait (&threadPtr->cond, &threadPtr->threadMutex, NULL);
}
- /*
- * We have to release the structure before trying to access the list again
- * or we can run into deadlock with a thread at [1] (see above) because of
- * us holding the structure and the other holding the list. There is no
- * problem with dangling pointers here as 'waitedUpon == 1' is still valid
- * and any other thread will error out and not come to this place. IOW,
- * the fact that we are here also means that no other thread came here
- * before us and is able to delete the structure.
+ /* We have to release the structure before trying to access the list
+ * again or we can run into deadlock with a thread at [1] (see above)
+ * because of us holding the structure and the other holding the list.
+ * There is no problem with dangling pointers here as 'waitedUpon == 1'
+ * is still valid and any other thread will error out and not come to
+ * this place. IOW, the fact that we are here also means that no other
+ * thread came here before us and is able to delete the structure.
*/
- Tcl_MutexUnlock(&threadPtr->threadMutex);
- Tcl_MutexLock(&joinMutex);
+ Tcl_MutexUnlock (&threadPtr->threadMutex);
+ Tcl_MutexLock (&joinMutex);
- /*
- * We have to search the list again as its structure may (may, almost
+ /* We have to search the list again as its structure may (may, almost
* certainly) have changed while we were waiting. Especially now is the
- * time to compute the predecessor in the list. Any earlier result can be
- * dangling by now.
+ * time to compute the predecessor in the list. Any earlier result can
+ * be dangling by now.
*/
if (firstThreadPtr == threadPtr) {
- firstThreadPtr = threadPtr->nextThreadPtr;
+ firstThreadPtr = threadPtr->nextThreadPtr;
} else {
- JoinableThread *prevThreadPtr = firstThreadPtr;
+ JoinableThread* prevThreadPtr;
+
+ for (prevThreadPtr = firstThreadPtr;
+ prevThreadPtr->nextThreadPtr != threadPtr;
+ prevThreadPtr = prevThreadPtr->nextThreadPtr)
+ /* empty body */
+ ;
- while (prevThreadPtr->nextThreadPtr != threadPtr) {
- prevThreadPtr = prevThreadPtr->nextThreadPtr;
- }
prevThreadPtr->nextThreadPtr = threadPtr->nextThreadPtr;
}
- Tcl_MutexUnlock(&joinMutex);
+ Tcl_MutexUnlock (&joinMutex);
- /*
- * [3] Now that the structure is not part of the list anymore no other
+ /* [3] Now that the structure is not part of the list anymore no other
* thread can acquire its mutex from now on. But it is possible that
- * another thread is still holding the mutex though, see location [2]. So
- * we have to acquire the mutex one more time to wait for that thread to
- * finish. We can (and have to) release the mutex immediately.
+ * another thread is still holding the mutex though, see location [2].
+ * So we have to acquire the mutex one more time to wait for that thread
+ * to finish. We can (and have to) release the mutex immediately.
*/
- Tcl_MutexLock(&threadPtr->threadMutex);
- Tcl_MutexUnlock(&threadPtr->threadMutex);
+ Tcl_MutexLock (&threadPtr->threadMutex);
+ Tcl_MutexUnlock (&threadPtr->threadMutex);
- /*
- * Copy the result to us, finalize the synchronisation objects, then free
- * the structure and return.
+ /* Copy the result to us, finalize the synchronisation objects, then
+ * free the structure and return.
*/
*result = threadPtr->result;
- Tcl_ConditionFinalize(&threadPtr->cond);
- Tcl_MutexFinalize(&threadPtr->threadMutex);
- ckfree(threadPtr);
+ Tcl_ConditionFinalize (&threadPtr->cond);
+ Tcl_MutexFinalize (&threadPtr->threadMutex);
+ ckfree ((VOID*) threadPtr);
return TCL_OK;
}
@@ -212,37 +211,39 @@ TclJoinThread(
* TclRememberJoinableThread --
*
* This procedure remebers a thread as joinable. Only a call to
- * TclJoinThread will remove the structre created (and initialized) here.
- * IOW, not waiting upon a joinable thread will cause memory leaks.
+ * TclJoinThread will remove the structre created (and initialized)
+ * here. IOW, not waiting upon a joinable thread will cause memory
+ * leaks.
*
* Results:
* None.
*
* Side effects:
- * Allocates memory, adds it to the global list of all joinable threads.
+ * Allocates memory, adds it to the global list of all joinable
+ * threads.
*
*----------------------------------------------------------------------
*/
-void
-TclRememberJoinableThread(
- Tcl_ThreadId id) /* The thread to remember as joinable */
+VOID
+TclRememberJoinableThread(id)
+ Tcl_ThreadId id; /* The thread to remember as joinable */
{
- JoinableThread *threadPtr;
+ JoinableThread* threadPtr;
- threadPtr = ckalloc(sizeof(JoinableThread));
- threadPtr->id = id;
- threadPtr->done = 0;
- threadPtr->waitedUpon = 0;
+ threadPtr = (JoinableThread*) ckalloc (sizeof (JoinableThread));
+ threadPtr->id = id;
+ threadPtr->done = 0;
+ threadPtr->waitedUpon = 0;
threadPtr->threadMutex = (Tcl_Mutex) NULL;
- threadPtr->cond = (Tcl_Condition) NULL;
+ threadPtr->cond = (Tcl_Condition) NULL;
- Tcl_MutexLock(&joinMutex);
+ Tcl_MutexLock (&joinMutex);
threadPtr->nextThreadPtr = firstThreadPtr;
- firstThreadPtr = threadPtr;
+ firstThreadPtr = threadPtr;
- Tcl_MutexUnlock(&joinMutex);
+ Tcl_MutexUnlock (&joinMutex);
}
/*
@@ -250,9 +251,9 @@ TclRememberJoinableThread(
*
* TclSignalExitThread --
*
- * This procedure signals that the specified thread is done with its
- * work. If the thread is joinable this signal is propagated to the
- * thread waiting upon it.
+ * This procedure signals that the specified thread is done with
+ * its work. If the thread is joinable this signal is propagated
+ * to the thread waiting upon it.
*
* Results:
* None.
@@ -263,54 +264,46 @@ TclRememberJoinableThread(
*----------------------------------------------------------------------
*/
-void
-TclSignalExitThread(
- Tcl_ThreadId id, /* Id of the thread signaling its exit. */
- int result) /* The result from the thread. */
+VOID
+TclSignalExitThread(id,result)
+ Tcl_ThreadId id; /* Id of the thread signaling its exit */
+ int result; /* The result from the thread */
{
- JoinableThread *threadPtr;
+ JoinableThread* threadPtr;
- Tcl_MutexLock(&joinMutex);
+ Tcl_MutexLock (&joinMutex);
- threadPtr = firstThreadPtr;
- while ((threadPtr != NULL) && (threadPtr->id != id)) {
- threadPtr = threadPtr->nextThreadPtr;
- }
+ for (threadPtr = firstThreadPtr;
+ (threadPtr != (JoinableThread*) NULL) && (threadPtr->id != id);
+ threadPtr = threadPtr->nextThreadPtr)
+ /* empty body */
+ ;
- if (threadPtr == NULL) {
- /*
- * Thread not found. Not joinable. No problem, nothing to do.
+ if (threadPtr == (JoinableThread*) NULL) {
+ /* Thread not found. Not joinable. No problem, nothing to do.
*/
- Tcl_MutexUnlock(&joinMutex);
+ Tcl_MutexUnlock (&joinMutex);
return;
}
- /*
- * Switch over the exclusive access from the list to the structure, then
- * store the result, set the flag and notify the waiting thread, provided
- * that it exists. The order of lock/unlock ensures that a thread entering
- * 'TclJoinThread' will not interfere with us.
+ /* Switch over the exclusive access from the list to the structure,
+ * then store the result, set the flag and notify the waiting thread,
+ * provided that it exists. The order of lock/unlock ensures that a
+ * thread entering 'TclJoinThread' will not interfere with us.
*/
- Tcl_MutexLock(&threadPtr->threadMutex);
- Tcl_MutexUnlock(&joinMutex);
+ Tcl_MutexLock (&threadPtr->threadMutex);
+ Tcl_MutexUnlock (&joinMutex);
- threadPtr->done = 1;
+ threadPtr->done = 1;
threadPtr->result = result;
if (threadPtr->waitedUpon) {
- Tcl_ConditionNotify(&threadPtr->cond);
+ Tcl_ConditionNotify (&threadPtr->cond);
}
- Tcl_MutexUnlock(&threadPtr->threadMutex);
+ Tcl_MutexUnlock (&threadPtr->threadMutex);
}
-#endif /* WIN32 */
-
-/*
- * Local Variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * End:
- */
+
+#endif /* WIN32 || MAC_TCL */