summaryrefslogtreecommitdiffstats
path: root/generic/tclAsync.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclAsync.c')
-rw-r--r--generic/tclAsync.c96
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: