diff options
Diffstat (limited to 'generic/tclThreadJoin.c')
-rw-r--r-- | generic/tclThreadJoin.c | 313 |
1 files changed, 160 insertions, 153 deletions
diff --git a/generic/tclThreadJoin.c b/generic/tclThreadJoin.c index f3c6abd..3a905b5 100644 --- a/generic/tclThreadJoin.c +++ b/generic/tclThreadJoin.c @@ -1,69 +1,66 @@ -/* +/* * tclThreadJoin.c -- * - * 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. + * 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. * * 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" -#if defined(WIN32) || defined(MAC_TCL) +#ifdef WIN32 -/* 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; - - /* *---------------------------------------------------------------------- * * 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 @@ -72,135 +69,139 @@ 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(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. */ +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. */ { - /* Steps done here: + JoinableThread *threadPtr; + + /* + * 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. */ - JoinableThread* threadPtr; + Tcl_MutexLock(&joinMutex); - Tcl_MutexLock (&joinMutex); - - for (threadPtr = firstThreadPtr; - (threadPtr != (JoinableThread*) NULL) && (threadPtr->id != id); - threadPtr = threadPtr->nextThreadPtr) - /* empty body */ - ; + threadPtr = firstThreadPtr; + while (threadPtr!=NULL && threadPtr->id!=id) { + threadPtr = threadPtr->nextThreadPtr; + } - if (threadPtr == (JoinableThread*) NULL) { - /* Thread not found. Either not joinable, or already waited - * upon and exited. Whatever, an error is in order. + if (threadPtr == 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; - - for (prevThreadPtr = firstThreadPtr; - prevThreadPtr->nextThreadPtr != threadPtr; - prevThreadPtr = prevThreadPtr->nextThreadPtr) - /* empty body */ - ; + JoinableThread *prevThreadPtr = firstThreadPtr; + 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 ((VOID*) threadPtr); + Tcl_ConditionFinalize(&threadPtr->cond); + Tcl_MutexFinalize(&threadPtr->threadMutex); + ckfree((char *) threadPtr); return TCL_OK; } @@ -211,39 +212,37 @@ TclJoinThread(id, result) * 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(id) - Tcl_ThreadId id; /* The thread to remember as joinable */ +void +TclRememberJoinableThread( + Tcl_ThreadId id) /* The thread to remember as joinable */ { - JoinableThread* threadPtr; + JoinableThread *threadPtr; - threadPtr = (JoinableThread*) 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); } /* @@ -251,9 +250,9 @@ TclRememberJoinableThread(id) * * 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. @@ -264,46 +263,54 @@ TclRememberJoinableThread(id) *---------------------------------------------------------------------- */ -VOID -TclSignalExitThread(id,result) - Tcl_ThreadId id; /* Id of the thread signaling its exit */ - int result; /* The result from the thread */ +void +TclSignalExitThread( + 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); - for (threadPtr = firstThreadPtr; - (threadPtr != (JoinableThread*) NULL) && (threadPtr->id != id); - threadPtr = threadPtr->nextThreadPtr) - /* empty body */ - ; + threadPtr = firstThreadPtr; + while ((threadPtr != NULL) && (threadPtr->id != id)) { + threadPtr = threadPtr->nextThreadPtr; + } - if (threadPtr == (JoinableThread*) NULL) { - /* Thread not found. Not joinable. No problem, nothing to do. + if (threadPtr == 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 || MAC_TCL */ +#endif /* WIN32 */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ |