diff options
Diffstat (limited to 'generic/tclAsync.c')
-rw-r--r-- | generic/tclAsync.c | 96 |
1 files changed, 63 insertions, 33 deletions
diff --git a/generic/tclAsync.c b/generic/tclAsync.c index ce29235..14804e4 100644 --- a/generic/tclAsync.c +++ b/generic/tclAsync.c @@ -10,8 +10,6 @@ * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tclAsync.c,v 1.8 2005/07/19 22:45:19 dkf Exp $ */ #include "tclInt.h" @@ -52,12 +50,12 @@ typedef struct ThreadSpecificData { AsyncHandler *lastHandler; /* Last handler or NULL. */ int asyncReady; /* This is set to 1 whenever a handler becomes * ready and it is cleared to zero whenever - * Tcl_AsyncInvoke is called. It can be + * Tcl_AsyncInvoke is called. It can be * checked elsewhere in the application by * calling Tcl_AsyncReady to see if * Tcl_AsyncInvoke should be invoked. */ int asyncActive; /* Indicates whether Tcl_AsyncInvoke is - * currently working. If so then we won't set + * currently working. If so then we won't set * asyncReady again until Tcl_AsyncInvoke * returns. */ Tcl_Mutex asyncMutex; /* Thread-specific AsyncHandler linked-list @@ -83,7 +81,7 @@ static Tcl_ThreadDataKey dataKey; */ void -TclFinalizeAsync() +TclFinalizeAsync(void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); @@ -112,15 +110,15 @@ TclFinalizeAsync() */ Tcl_AsyncHandler -Tcl_AsyncCreate(proc, clientData) - Tcl_AsyncProc *proc; /* Procedure to call when handler is +Tcl_AsyncCreate( + Tcl_AsyncProc *proc, /* Procedure to call when handler is * invoked. */ - ClientData clientData; /* Argument to pass to handler. */ + ClientData clientData) /* Argument to pass to handler. */ { AsyncHandler *asyncPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - asyncPtr = (AsyncHandler *) ckalloc(sizeof(AsyncHandler)); + asyncPtr = ckalloc(sizeof(AsyncHandler)); asyncPtr->ready = 0; asyncPtr->nextPtr = NULL; asyncPtr->proc = proc; @@ -145,7 +143,7 @@ Tcl_AsyncCreate(proc, clientData) * Tcl_AsyncMark -- * * This procedure is called to request that an asynchronous handler be - * invoked as soon as possible. It's typically called from an interrupt + * invoked as soon as possible. It's typically called from an interrupt * handler, where it isn't safe to do anything that depends on or * modifies application state. * @@ -159,8 +157,8 @@ Tcl_AsyncCreate(proc, clientData) */ void -Tcl_AsyncMark(async) - Tcl_AsyncHandler async; /* Token for handler. */ +Tcl_AsyncMark( + Tcl_AsyncHandler async) /* Token for handler. */ { AsyncHandler *token = (AsyncHandler *) async; @@ -192,11 +190,11 @@ Tcl_AsyncMark(async) */ int -Tcl_AsyncInvoke(interp, code) - Tcl_Interp *interp; /* If invoked from Tcl_Eval just after +Tcl_AsyncInvoke( + Tcl_Interp *interp, /* If invoked from Tcl_Eval just after * completing a command, points to - * interpreter. Otherwise it is NULL. */ - int code; /* If interp is non-NULL, this gives + * interpreter. Otherwise it is NULL. */ + int code) /* If interp is non-NULL, this gives * completion code from command that just * completed. */ { @@ -237,7 +235,7 @@ Tcl_AsyncInvoke(interp, code) } asyncPtr->ready = 0; Tcl_MutexUnlock(&tsdPtr->asyncMutex); - code = (*asyncPtr->proc)(asyncPtr->clientData, interp, code); + code = asyncPtr->proc(asyncPtr->clientData, interp, code); Tcl_MutexLock(&tsdPtr->asyncMutex); } tsdPtr->asyncActive = 0; @@ -259,35 +257,60 @@ Tcl_AsyncInvoke(interp, code) * Side effects: * The state associated with the handler is deleted. * + * Failure to locate the handler in current thread private list + * of async handlers will result in panic; exception: the list + * is already empty (potential trouble?). + * Consequently, threads should create and delete handlers + * themselves. I.e. a handler created by one should not be + * deleted by some other thread. + * *---------------------------------------------------------------------- */ void -Tcl_AsyncDelete(async) - Tcl_AsyncHandler async; /* Token for handler to delete. */ +Tcl_AsyncDelete( + Tcl_AsyncHandler async) /* Token for handler to delete. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); AsyncHandler *asyncPtr = (AsyncHandler *) async; - AsyncHandler *prevPtr; + AsyncHandler *prevPtr, *thisPtr; + + /* + * Assure early handling of the constraint + */ + + if (asyncPtr->originThrdId != Tcl_GetCurrentThread()) { + Tcl_Panic("Tcl_AsyncDelete: async handler deleted by the wrong thread"); + } + + /* + * If we come to this point when TSD's for the current + * thread have already been garbage-collected, we are + * in the _serious_ trouble. OTOH, we tolerate calling + * with already cleaned-up handler list (should we?). + */ Tcl_MutexLock(&tsdPtr->asyncMutex); - if (tsdPtr->firstHandler == asyncPtr) { - tsdPtr->firstHandler = asyncPtr->nextPtr; - if (tsdPtr->firstHandler == NULL) { - tsdPtr->lastHandler = NULL; + if (tsdPtr->firstHandler != NULL) { + prevPtr = thisPtr = tsdPtr->firstHandler; + while (thisPtr != NULL && thisPtr != asyncPtr) { + prevPtr = thisPtr; + thisPtr = thisPtr->nextPtr; } - } else { - prevPtr = tsdPtr->firstHandler; - while (prevPtr->nextPtr != asyncPtr) { - prevPtr = prevPtr->nextPtr; + if (thisPtr == NULL) { + Tcl_Panic("Tcl_AsyncDelete: cannot find async handler"); + } + if (asyncPtr == tsdPtr->firstHandler) { + tsdPtr->firstHandler = asyncPtr->nextPtr; + } else { + prevPtr->nextPtr = asyncPtr->nextPtr; } - prevPtr->nextPtr = asyncPtr->nextPtr; - if (tsdPtr->lastHandler == asyncPtr) { + if (asyncPtr == tsdPtr->lastHandler) { tsdPtr->lastHandler = prevPtr; } } Tcl_MutexUnlock(&tsdPtr->asyncMutex); - ckfree((char *) asyncPtr); + ckfree(asyncPtr); } /* @@ -296,7 +319,7 @@ Tcl_AsyncDelete(async) * Tcl_AsyncReady -- * * This procedure can be used to tell whether Tcl_AsyncInvoke needs to be - * called. This procedure is the external interface for checking the + * called. This procedure is the external interface for checking the * thread-specific asyncReady variable. * * Results: @@ -310,11 +333,18 @@ Tcl_AsyncDelete(async) */ int -Tcl_AsyncReady() +Tcl_AsyncReady(void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); return tsdPtr->asyncReady; } + +int * +TclGetAsyncReadyPtr(void) +{ + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + return &(tsdPtr->asyncReady); +} /* * Local Variables: |