diff options
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tclAsync.c | 157 | ||||
-rw-r--r-- | generic/tclInt.decls | 10 | ||||
-rw-r--r-- | generic/tclIntPlatDecls.h | 12 | ||||
-rw-r--r-- | generic/tclStubInit.c | 4 |
4 files changed, 117 insertions, 66 deletions
diff --git a/generic/tclAsync.c b/generic/tclAsync.c index fc80385..d0ac056 100644 --- a/generic/tclAsync.c +++ b/generic/tclAsync.c @@ -12,12 +12,15 @@ * 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.4 1999/04/16 00:46:42 stanton Exp $ + * RCS: @(#) $Id: tclAsync.c,v 1.4.12.1 2001/09/01 22:53:45 davygrvy Exp $ */ #include "tclInt.h" #include "tclPort.h" +/* Forward declaration */ +struct ThreadSpecificData; + /* * One of the following structures exists for each asynchronous * handler: @@ -33,34 +36,74 @@ typedef struct AsyncHandler { * is invoked. */ ClientData clientData; /* Value to pass to handler when it * is invoked. */ + struct ThreadSpecificData *originTsd; + /* Used in Tcl_AsyncMark to modify thread- + * specific data from outside the thread + * it is associated to. */ + Tcl_ThreadId originThrdId; /* Origin thread where this token was + * created and where it will be + * yielded. */ } AsyncHandler; -/* - * The variables below maintain a list of all existing handlers. - */ -static AsyncHandler *firstHandler; /* First handler defined for process, - * or NULL if none. */ -static AsyncHandler *lastHandler; /* Last handler or NULL. */ +typedef struct ThreadSpecificData { + /* + * The variables below maintain a list of all existing handlers + * specific to the calling thread. + */ + AsyncHandler *firstHandler; /* First handler defined for process, + * or NULL if none. */ + AsyncHandler *lastHandler; /* Last handler or NULL. */ -TCL_DECLARE_MUTEX(asyncMutex) /* Process-wide async handler lock */ + /* + * The variable below is set to 1 whenever a handler becomes ready and + * it is cleared to zero whenever Tcl_AsyncInvoke is called. It can be + * checked elsewhere in the application by calling Tcl_AsyncReady to see + * if Tcl_AsyncInvoke should be invoked. + */ -/* - * The variable below is set to 1 whenever a handler becomes ready and - * it is cleared to zero whenever 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 asyncReady; + + /* + * The variable below indicates whether Tcl_AsyncInvoke is currently + * working. If so then we won't set asyncReady again until + * Tcl_AsyncInvoke returns. + */ -static int asyncReady = 0; + int asyncActive; + Tcl_Mutex asyncMutex; /* Thread-specific AsyncHandler linked-list lock */ + +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; + + /* - * The variable below indicates whether Tcl_AsyncInvoke is currently - * working. If so then we won't set asyncReady again until - * Tcl_AsyncInvoke returns. + *---------------------------------------------------------------------- + * + * TclFinalizeAsync -- + * + * Finalizes the mutex in the thread local data structure for the + * async subsystem. + * + * Results: + * None. + * + * Side effects: + * Forgets knowledge of the mutex should it have been created. + * + *---------------------------------------------------------------------- */ -static int asyncActive = 0; +void +TclFinalizeAsync() +{ + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + if (tsdPtr->asyncMutex != NULL) { + Tcl_MutexFinalize(&tsdPtr->asyncMutex); + } +} /* *---------------------------------------------------------------------- @@ -88,20 +131,24 @@ Tcl_AsyncCreate(proc, clientData) ClientData clientData; /* Argument to pass to handler. */ { AsyncHandler *asyncPtr; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); asyncPtr = (AsyncHandler *) ckalloc(sizeof(AsyncHandler)); asyncPtr->ready = 0; asyncPtr->nextPtr = NULL; asyncPtr->proc = proc; asyncPtr->clientData = clientData; - Tcl_MutexLock(&asyncMutex); - if (firstHandler == NULL) { - firstHandler = asyncPtr; + asyncPtr->originTsd = tsdPtr; + asyncPtr->originThrdId = Tcl_GetCurrentThread(); + + Tcl_MutexLock(&tsdPtr->asyncMutex); + if (tsdPtr->firstHandler == NULL) { + tsdPtr->firstHandler = asyncPtr; } else { - lastHandler->nextPtr = asyncPtr; + tsdPtr->lastHandler->nextPtr = asyncPtr; } - lastHandler = asyncPtr; - Tcl_MutexUnlock(&asyncMutex); + tsdPtr->lastHandler = asyncPtr; + Tcl_MutexUnlock(&tsdPtr->asyncMutex); return (Tcl_AsyncHandler) asyncPtr; } @@ -128,13 +175,15 @@ void Tcl_AsyncMark(async) Tcl_AsyncHandler async; /* Token for handler. */ { - Tcl_MutexLock(&asyncMutex); - ((AsyncHandler *) async)->ready = 1; - if (!asyncActive) { - asyncReady = 1; - TclpAsyncMark(async); + AsyncHandler *token = (AsyncHandler *) async; + + Tcl_MutexLock(&token->originTsd->asyncMutex); + token->ready = 1; + if (!token->originTsd->asyncActive) { + token->originTsd->asyncReady = 1; + Tcl_ThreadAlert(token->originThrdId); } - Tcl_MutexUnlock(&asyncMutex); + Tcl_MutexUnlock(&token->originTsd->asyncMutex); } /* @@ -167,14 +216,16 @@ Tcl_AsyncInvoke(interp, code) * just completed. */ { AsyncHandler *asyncPtr; - Tcl_MutexLock(&asyncMutex); + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + Tcl_MutexLock(&tsdPtr->asyncMutex); - if (asyncReady == 0) { - Tcl_MutexUnlock(&asyncMutex); + if (tsdPtr->asyncReady == 0) { + Tcl_MutexUnlock(&tsdPtr->asyncMutex); return code; } - asyncReady = 0; - asyncActive = 1; + tsdPtr->asyncReady = 0; + tsdPtr->asyncActive = 1; if (interp == NULL) { code = 0; } @@ -191,7 +242,7 @@ Tcl_AsyncInvoke(interp, code) */ while (1) { - for (asyncPtr = firstHandler; asyncPtr != NULL; + for (asyncPtr = tsdPtr->firstHandler; asyncPtr != NULL; asyncPtr = asyncPtr->nextPtr) { if (asyncPtr->ready) { break; @@ -201,12 +252,12 @@ Tcl_AsyncInvoke(interp, code) break; } asyncPtr->ready = 0; - Tcl_MutexUnlock(&asyncMutex); + Tcl_MutexUnlock(&tsdPtr->asyncMutex); code = (*asyncPtr->proc)(asyncPtr->clientData, interp, code); - Tcl_MutexLock(&asyncMutex); + Tcl_MutexLock(&tsdPtr->asyncMutex); } - asyncActive = 0; - Tcl_MutexUnlock(&asyncMutex); + tsdPtr->asyncActive = 0; + Tcl_MutexUnlock(&tsdPtr->asyncMutex); return code; } @@ -231,26 +282,27 @@ void Tcl_AsyncDelete(async) Tcl_AsyncHandler async; /* Token for handler to delete. */ { + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); AsyncHandler *asyncPtr = (AsyncHandler *) async; AsyncHandler *prevPtr; - Tcl_MutexLock(&asyncMutex); - if (firstHandler == asyncPtr) { - firstHandler = asyncPtr->nextPtr; - if (firstHandler == NULL) { - lastHandler = NULL; + Tcl_MutexLock(&tsdPtr->asyncMutex); + if (tsdPtr->firstHandler == asyncPtr) { + tsdPtr->firstHandler = asyncPtr->nextPtr; + if (tsdPtr->firstHandler == NULL) { + tsdPtr->lastHandler = NULL; } } else { - prevPtr = firstHandler; + prevPtr = tsdPtr->firstHandler; while (prevPtr->nextPtr != asyncPtr) { prevPtr = prevPtr->nextPtr; } prevPtr->nextPtr = asyncPtr->nextPtr; - if (lastHandler == asyncPtr) { - lastHandler = prevPtr; + if (tsdPtr->lastHandler == asyncPtr) { + tsdPtr->lastHandler = prevPtr; } } - Tcl_MutexUnlock(&asyncMutex); + Tcl_MutexUnlock(&tsdPtr->asyncMutex); ckfree((char *) asyncPtr); } @@ -261,7 +313,7 @@ Tcl_AsyncDelete(async) * * This procedure can be used to tell whether Tcl_AsyncInvoke * needs to be called. This procedure is the external interface - * for checking the internal asyncReady variable. + * for checking the thread-specific asyncReady variable. * * Results: * The return value is 1 whenever a handler is ready and is 0 @@ -276,5 +328,6 @@ Tcl_AsyncDelete(async) int Tcl_AsyncReady() { - return asyncReady; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + return tsdPtr->asyncReady; } diff --git a/generic/tclInt.decls b/generic/tclInt.decls index 215a058..3b945ba 100644 --- a/generic/tclInt.decls +++ b/generic/tclInt.decls @@ -10,7 +10,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: tclInt.decls,v 1.20.2.2 2001/04/04 21:22:18 hobbs Exp $ +# RCS: @(#) $Id: tclInt.decls,v 1.20.2.3 2001/09/01 22:53:45 davygrvy Exp $ library tcl @@ -803,9 +803,11 @@ declare 19 win { declare 20 win { void TclWinAddProcess(HANDLE hProcess, DWORD id) } -declare 21 win { - void TclpAsyncMark(Tcl_AsyncHandler async) -} +# Removed permanently from 8.3.4 to match 8.4a2's removal +# +# declare 21 win { +# void TclpAsyncMark(Tcl_AsyncHandler async) +# } # Added in 8.1: declare 22 win { diff --git a/generic/tclIntPlatDecls.h b/generic/tclIntPlatDecls.h index 5462b90..9a55e15 100644 --- a/generic/tclIntPlatDecls.h +++ b/generic/tclIntPlatDecls.h @@ -9,7 +9,7 @@ * Copyright (c) 1998-1999 by Scriptics Corporation. * All rights reserved. * - * RCS: @(#) $Id: tclIntPlatDecls.h,v 1.8.2.2 2001/08/28 00:12:45 hobbs Exp $ + * RCS: @(#) $Id: tclIntPlatDecls.h,v 1.8.2.3 2001/09/01 22:53:45 davygrvy Exp $ */ #ifndef _TCLINTPLATDECLS @@ -115,8 +115,7 @@ EXTERN TclFile TclpOpenFile _ANSI_ARGS_((CONST char * fname, /* 20 */ EXTERN void TclWinAddProcess _ANSI_ARGS_((HANDLE hProcess, DWORD id)); -/* 21 */ -EXTERN void TclpAsyncMark _ANSI_ARGS_((Tcl_AsyncHandler async)); +/* Slot 21 is reserved */ /* 22 */ EXTERN TclFile TclpCreateTempFile _ANSI_ARGS_(( CONST char * contents)); @@ -236,7 +235,7 @@ typedef struct TclIntPlatStubs { TclFile (*tclpMakeFile) _ANSI_ARGS_((Tcl_Channel channel, int direction)); /* 18 */ TclFile (*tclpOpenFile) _ANSI_ARGS_((CONST char * fname, int mode)); /* 19 */ void (*tclWinAddProcess) _ANSI_ARGS_((HANDLE hProcess, DWORD id)); /* 20 */ - void (*tclpAsyncMark) _ANSI_ARGS_((Tcl_AsyncHandler async)); /* 21 */ + void *reserved21; TclFile (*tclpCreateTempFile) _ANSI_ARGS_((CONST char * contents)); /* 22 */ char * (*tclpGetTZName) _ANSI_ARGS_((int isdst)); /* 23 */ char * (*tclWinNoBackslash) _ANSI_ARGS_((char * path)); /* 24 */ @@ -399,10 +398,7 @@ extern TclIntPlatStubs *tclIntPlatStubsPtr; #define TclWinAddProcess \ (tclIntPlatStubsPtr->tclWinAddProcess) /* 20 */ #endif -#ifndef TclpAsyncMark -#define TclpAsyncMark \ - (tclIntPlatStubsPtr->tclpAsyncMark) /* 21 */ -#endif +/* Slot 21 is reserved */ #ifndef TclpCreateTempFile #define TclpCreateTempFile \ (tclIntPlatStubsPtr->tclpCreateTempFile) /* 22 */ diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c index 2ca7c1d..1f0b58f 100644 --- a/generic/tclStubInit.c +++ b/generic/tclStubInit.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclStubInit.c,v 1.35.2.3 2001/08/28 00:12:45 hobbs Exp $ + * RCS: @(#) $Id: tclStubInit.c,v 1.35.2.4 2001/09/01 22:53:45 davygrvy Exp $ */ #include "tclInt.h" @@ -277,7 +277,7 @@ TclIntPlatStubs tclIntPlatStubs = { TclpMakeFile, /* 18 */ TclpOpenFile, /* 19 */ TclWinAddProcess, /* 20 */ - TclpAsyncMark, /* 21 */ + NULL, /* 21 */ TclpCreateTempFile, /* 22 */ TclpGetTZName, /* 23 */ TclWinNoBackslash, /* 24 */ |