diff options
Diffstat (limited to 'tcl8.6/generic/tclThreadJoin.c')
-rw-r--r-- | tcl8.6/generic/tclThreadJoin.c | 316 |
1 files changed, 0 insertions, 316 deletions
diff --git a/tcl8.6/generic/tclThreadJoin.c b/tcl8.6/generic/tclThreadJoin.c deleted file mode 100644 index 5c70a62..0000000 --- a/tcl8.6/generic/tclThreadJoin.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - * 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. - * - * 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. - */ - -#include "tclInt.h" - -#ifdef _WIN32 - -/* - * 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. */ -} 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'. - */ - -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. - * - * Results: - * A standard tcl result signaling the overall success/failure of the - * operation and an integer result delivered by the thread which was - * waited upon. - * - * Side effects: - * Deallocates the memory allocated by TclRememberJoinableThread. - * 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. */ -{ - 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. - * 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, - * 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); - - threadPtr = firstThreadPtr; - while (threadPtr!=NULL && threadPtr->id!=id) { - threadPtr = threadPtr->nextThreadPtr; - } - - 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; - } - - /* - * [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); - - /* - * [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); - return TCL_ERROR; - } - - /* - * We are waiting now, let other threads recognize this. - */ - - threadPtr->waitedUpon = 1; - - while (!threadPtr->done) { - 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. - */ - - Tcl_MutexUnlock(&threadPtr->threadMutex); - Tcl_MutexLock(&joinMutex); - - /* - * 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. - */ - - if (firstThreadPtr == threadPtr) { - firstThreadPtr = threadPtr->nextThreadPtr; - } else { - JoinableThread *prevThreadPtr = firstThreadPtr; - - while (prevThreadPtr->nextThreadPtr != threadPtr) { - prevThreadPtr = prevThreadPtr->nextThreadPtr; - } - prevThreadPtr->nextThreadPtr = threadPtr->nextThreadPtr; - } - - Tcl_MutexUnlock(&joinMutex); - - /* - * [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. - */ - - Tcl_MutexLock(&threadPtr->threadMutex); - Tcl_MutexUnlock(&threadPtr->threadMutex); - - /* - * 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); - - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * 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. - * - * Results: - * None. - * - * Side effects: - * Allocates memory, adds it to the global list of all joinable threads. - * - *---------------------------------------------------------------------- - */ - -void -TclRememberJoinableThread( - Tcl_ThreadId id) /* The thread to remember as joinable */ -{ - JoinableThread *threadPtr; - - threadPtr = ckalloc(sizeof(JoinableThread)); - threadPtr->id = id; - threadPtr->done = 0; - threadPtr->waitedUpon = 0; - threadPtr->threadMutex = (Tcl_Mutex) NULL; - threadPtr->cond = (Tcl_Condition) NULL; - - Tcl_MutexLock(&joinMutex); - - threadPtr->nextThreadPtr = firstThreadPtr; - firstThreadPtr = threadPtr; - - Tcl_MutexUnlock(&joinMutex); -} - -/* - *---------------------------------------------------------------------- - * - * 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. - * - * Results: - * None. - * - * Side effects: - * Modifies the associated structure to hold the result. - * - *---------------------------------------------------------------------- - */ - -void -TclSignalExitThread( - Tcl_ThreadId id, /* Id of the thread signaling its exit. */ - int result) /* The result from the thread. */ -{ - JoinableThread *threadPtr; - - Tcl_MutexLock(&joinMutex); - - threadPtr = firstThreadPtr; - while ((threadPtr != NULL) && (threadPtr->id != id)) { - threadPtr = threadPtr->nextThreadPtr; - } - - if (threadPtr == NULL) { - /* - * Thread not found. Not joinable. No problem, nothing to do. - */ - - 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. - */ - - Tcl_MutexLock(&threadPtr->threadMutex); - Tcl_MutexUnlock(&joinMutex); - - threadPtr->done = 1; - threadPtr->result = result; - - if (threadPtr->waitedUpon) { - Tcl_ConditionNotify(&threadPtr->cond); - } - - Tcl_MutexUnlock(&threadPtr->threadMutex); -} -#endif /* _WIN32 */ - -/* - * Local Variables: - * mode: c - * c-basic-offset: 4 - * fill-column: 78 - * End: - */ |