diff options
Diffstat (limited to 'generic/tclEvent.c')
| -rw-r--r-- | generic/tclEvent.c | 1035 |
1 files changed, 234 insertions, 801 deletions
diff --git a/generic/tclEvent.c b/generic/tclEvent.c index 1a2f8ca..c664b38 100644 --- a/generic/tclEvent.c +++ b/generic/tclEvent.c @@ -5,16 +5,15 @@ * background errors, exit handlers, and the "vwait" and "update" command * functions. * - * Copyright © 1990-1994 The Regents of the University of California. - * Copyright © 1994-1998 Sun Microsystems, Inc. - * Copyright © 2004 Zoran Vasiljevic. + * Copyright (c) 1990-1994 The Regents of the University of California. + * Copyright (c) 1994-1998 Sun Microsystems, Inc. + * Copyright (c) 2004 by Zoran Vasiljevic. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" -#include "tclUuid.h" /* * The data structure below is used to report background errors. One such @@ -38,7 +37,7 @@ typedef struct BgError { * pending background errors for the interpreter. */ -typedef struct { +typedef struct ErrAssocData { Tcl_Interp *interp; /* Interpreter in which error occurred. */ Tcl_Obj *cmdPrefix; /* First word(s) of the handler command */ BgError *firstBgPtr; /* First in list of all background errors @@ -50,26 +49,13 @@ typedef struct { } ErrAssocData; /* - * For each "vwait" event source a structure of the following type - * is used: - */ - -typedef struct { - int *donePtr; /* Pointer to flag to signal or NULL. */ - int sequence; /* Order of occurrence. */ - int mask; /* 0, or TCL_READABLE/TCL_WRITABLE. */ - Tcl_Obj *sourceObj; /* Name of the event source, either a - * variable name or channel name. */ -} VwaitItem; - -/* - * For each exit handler created with a call to Tcl_Create(Late)ExitHandler - * there is a structure of the following type: + * For each exit handler created with a call to Tcl_Create(Late)ExitHandler there is + * a structure of the following type: */ typedef struct ExitHandler { Tcl_ExitProc *proc; /* Function to call when process exits. */ - void *clientData; /* One word of information to pass to proc. */ + ClientData clientData; /* One word of information to pass to proc. */ struct ExitHandler *nextPtr;/* Next in list of all exit handlers for this * application, or NULL for end of list. */ } ExitHandler; @@ -88,24 +74,22 @@ static ExitHandler *firstLateExitPtr = NULL; TCL_DECLARE_MUTEX(exitMutex) /* - * This variable is set to 1 when Tcl_Exit is called. The variable is checked - * by TclInExit() to allow different behavior for exit-time processing, e.g., - * in closing of files and pipes. + * This variable is set to 1 when Tcl_Finalize is called, and at the end of + * its work, it is reset to 0. The variable is checked by TclInExit() to allow + * different behavior for exit-time processing, e.g. in closing of files and + * pipes. */ -static int inExit = 0; - +static int inFinalize = 0; static int subsystemsInitialized = 0; -static const char ENCODING_ERROR[] = "\n\t(encoding error in stderr)"; - /* - * This variable contains the application wide exit handler. It will be called - * by Tcl_Exit instead of the C-runtime exit if this variable is set to a - * non-NULL value. + * This variable contains the application wide exit handler. It will be + * called by Tcl_Exit instead of the C-runtime exit if this variable is set + * to a non-NULL value. */ -static TCL_NORETURN1 Tcl_ExitProc *appExitPtr = NULL; +static Tcl_ExitProc *appExitPtr = NULL; typedef struct ThreadSpecificData { ExitHandler *firstExitPtr; /* First in list of all exit handlers for this @@ -116,29 +100,23 @@ typedef struct ThreadSpecificData { } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; -#if TCL_THREADS +#ifdef TCL_THREADS typedef struct { Tcl_ThreadCreateProc *proc; /* Main() function of the thread */ - void *clientData; /* The one argument to Main() */ + ClientData clientData; /* The one argument to Main() */ } ThreadClientData; -static Tcl_ThreadCreateType NewThreadProc(void *clientData); +static Tcl_ThreadCreateType NewThreadProc(ClientData clientData); #endif /* TCL_THREADS */ /* * Prototypes for functions referenced only in this file: */ -static void BgErrorDeleteProc(void *clientData, +static void BgErrorDeleteProc(ClientData clientData, Tcl_Interp *interp); -static void HandleBgErrors(void *clientData); -static void VwaitChannelReadProc(void *clientData, int mask); -static void VwaitChannelWriteProc(void *clientData, int mask); -static void VwaitTimeoutProc(void *clientData); -static char * VwaitVarProc(void *clientData, - Tcl_Interp *interp, const char *name1, - const char *name2, int flags); -static void InvokeExitHandlers(void); -static void FinalizeThread(int quick); +static void HandleBgErrors(ClientData clientData); +static char * VwaitVarProc(ClientData clientData, Tcl_Interp *interp, + CONST char *name1, CONST char *name2, int flags); /* *---------------------------------------------------------------------- @@ -158,19 +136,15 @@ static void FinalizeThread(int quick); *---------------------------------------------------------------------- */ -#if !defined(TCL_NO_DEPRECATED) && TCL_MAJOR_VERSION < 9 -#undef Tcl_BackgroundError void Tcl_BackgroundError( Tcl_Interp *interp) /* Interpreter in which an error has * occurred. */ { - Tcl_BackgroundException(interp, TCL_ERROR); + TclBackgroundException(interp, TCL_ERROR); } -#endif /* TCL_NO_DEPRECATED */ - void -Tcl_BackgroundException( +TclBackgroundException( Tcl_Interp *interp, /* Interpreter in which an exception has * occurred. */ int code) /* The exception code value */ @@ -182,7 +156,7 @@ Tcl_BackgroundException( return; } - errPtr = (BgError*)ckalloc(sizeof(BgError)); + errPtr = (BgError *) ckalloc(sizeof(BgError)); errPtr->errorMsg = Tcl_GetObjResult(interp); Tcl_IncrRefCount(errPtr->errorMsg); errPtr->returnOpts = Tcl_GetReturnOptions(interp, code); @@ -190,10 +164,10 @@ Tcl_BackgroundException( errPtr->nextPtr = NULL; (void) TclGetBgErrorHandler(interp); - assocPtr = (ErrAssocData *)Tcl_GetAssocData(interp, "tclBgError", NULL); + assocPtr = (ErrAssocData *) Tcl_GetAssocData(interp, "tclBgError", NULL); if (assocPtr->firstBgPtr == NULL) { assocPtr->firstBgPtr = errPtr; - Tcl_DoWhenIdle(HandleBgErrors, assocPtr); + Tcl_DoWhenIdle(HandleBgErrors, (ClientData) assocPtr); } else { assocPtr->lastBgPtr->nextPtr = errPtr; } @@ -220,9 +194,9 @@ Tcl_BackgroundException( static void HandleBgErrors( - void *clientData) /* Pointer to ErrAssocData structure. */ + ClientData clientData) /* Pointer to ErrAssocData structure. */ { - ErrAssocData *assocPtr = (ErrAssocData *)clientData; + ErrAssocData *assocPtr = (ErrAssocData *) clientData; Tcl_Interp *interp = assocPtr->interp; BgError *errPtr; @@ -233,24 +207,23 @@ HandleBgErrors( * that could lead us here. */ - Tcl_Preserve(assocPtr); - Tcl_Preserve(interp); + Tcl_Preserve((ClientData) assocPtr); + Tcl_Preserve((ClientData) interp); while (assocPtr->firstBgPtr != NULL) { - int code; - Tcl_Size prefixObjc; + int code, prefixObjc; Tcl_Obj **prefixObjv, **tempObjv; /* - * Note we copy the handler command prefix each pass through, so we do - * support one handler setting another handler. + * Note we copy the handler command prefix each pass through, so + * we do support one handler setting another handler. */ Tcl_Obj *copyObj = TclListObjCopy(NULL, assocPtr->cmdPrefix); errPtr = assocPtr->firstBgPtr; - TclListObjGetElements(NULL, copyObj, &prefixObjc, &prefixObjv); - tempObjv = (Tcl_Obj**)ckalloc((prefixObjc+2) * sizeof(Tcl_Obj *)); + Tcl_ListObjGetElements(NULL, copyObj, &prefixObjc, &prefixObjv); + tempObjv = (Tcl_Obj **) ckalloc((prefixObjc+2)*sizeof(Tcl_Obj *)); memcpy(tempObjv, prefixObjv, prefixObjc*sizeof(Tcl_Obj *)); tempObjv[prefixObjc] = errPtr->errorMsg; tempObjv[prefixObjc+1] = errPtr->returnOpts; @@ -265,8 +238,8 @@ HandleBgErrors( Tcl_DecrRefCount(errPtr->errorMsg); Tcl_DecrRefCount(errPtr->returnOpts); assocPtr->firstBgPtr = errPtr->nextPtr; - ckfree(errPtr); - ckfree(tempObjv); + ckfree((char *) errPtr); + ckfree((char *) tempObjv); if (code == TCL_BREAK) { /* @@ -279,12 +252,12 @@ HandleBgErrors( assocPtr->firstBgPtr = errPtr->nextPtr; Tcl_DecrRefCount(errPtr->errorMsg); Tcl_DecrRefCount(errPtr->returnOpts); - ckfree(errPtr); + ckfree((char *) errPtr); } } else if ((code == TCL_ERROR) && !Tcl_IsSafe(interp)) { Tcl_Channel errChannel = Tcl_GetStdChannel(TCL_STDERR); - if (errChannel != NULL) { + if (errChannel != (Tcl_Channel) NULL) { Tcl_Obj *options = Tcl_GetReturnOptions(interp, code); Tcl_Obj *keyPtr, *valuePtr = NULL; @@ -296,13 +269,9 @@ HandleBgErrors( Tcl_WriteChars(errChannel, "error in background error handler:\n", -1); if (valuePtr) { - if (Tcl_WriteObj(errChannel, valuePtr) < 0) { - Tcl_WriteChars(errChannel, ENCODING_ERROR, -1); - } + Tcl_WriteObj(errChannel, valuePtr); } else { - if (Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp)) < 0) { - Tcl_WriteChars(errChannel, ENCODING_ERROR, -1); - } + Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp)); } Tcl_WriteChars(errChannel, "\n", 1); Tcl_Flush(errChannel); @@ -311,8 +280,8 @@ HandleBgErrors( } } assocPtr->lastBgPtr = NULL; - Tcl_Release(interp); - Tcl_Release(assocPtr); + Tcl_Release((ClientData) interp); + Tcl_Release((ClientData) assocPtr); } /* @@ -335,10 +304,10 @@ HandleBgErrors( int TclDefaultBgErrorHandlerObjCmd( - TCL_UNUSED(void *), + ClientData dummy, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ - Tcl_Obj *const objv[]) /* Argument objects. */ + Tcl_Obj *CONST objv[]) /* Argument objects. */ { Tcl_Obj *keyPtr, *valuePtr; Tcl_Obj *tempObjv[2]; @@ -361,7 +330,6 @@ TclDefaultBgErrorHandlerObjCmd( if (result != TCL_OK || valuePtr == NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "missing return option \"-level\"", -1)); - Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", (void *)NULL); return TCL_ERROR; } if (Tcl_GetIntFromObj(interp, valuePtr, &level) == TCL_ERROR) { @@ -374,7 +342,6 @@ TclDefaultBgErrorHandlerObjCmd( if (result != TCL_OK || valuePtr == NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "missing return option \"-code\"", -1)); - Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", (void *)NULL); return TCL_ERROR; } if (Tcl_GetIntFromObj(interp, valuePtr, &code) == TCL_ERROR) { @@ -382,26 +349,19 @@ TclDefaultBgErrorHandlerObjCmd( } if (level != 0) { - /* - * We're handling a TCL_RETURN exception. - */ - + /* We're handling a TCL_RETURN exception */ code = TCL_RETURN; } if (code == TCL_OK) { /* - * Somehow we got to exception handling with no exception. (Pass - * TCL_OK to Tcl_BackgroundException()?) Just return without doing - * anything. + * Somehow we got to exception handling with no exception. + * (Pass TCL_OK to TclBackgroundException()?) + * Just return without doing anything. */ - return TCL_OK; } - /* - * Construct the bgerror command. - */ - + /* Construct the bgerror command */ TclNewLiteralStringObj(tempObjv[0], "bgerror"); Tcl_IncrRefCount(tempObjv[0]); @@ -459,10 +419,7 @@ TclDefaultBgErrorHandlerObjCmd( saved = Tcl_SaveInterpState(interp, code); - /* - * Invoke the bgerror command. - */ - + /* Invoke the bgerror command. */ Tcl_AllowExceptions(interp); code = Tcl_EvalObjv(interp, 2, tempObjv, TCL_EVAL_GLOBAL); if (code == TCL_ERROR) { @@ -481,30 +438,25 @@ TclDefaultBgErrorHandlerObjCmd( TclObjInvoke(interp, 2, tempObjv, TCL_INVOKE_HIDDEN); } else { Tcl_Channel errChannel = Tcl_GetStdChannel(TCL_STDERR); - - if (errChannel != NULL) { + if (errChannel != (Tcl_Channel) NULL) { Tcl_Obj *resultPtr = Tcl_GetObjResult(interp); Tcl_IncrRefCount(resultPtr); if (Tcl_FindCommand(interp, "bgerror", NULL, TCL_GLOBAL_ONLY) == NULL) { Tcl_RestoreInterpState(interp, saved); - if (Tcl_WriteObj(errChannel, Tcl_GetVar2Ex(interp, - "errorInfo", NULL, TCL_GLOBAL_ONLY)) < 0) { - Tcl_WriteChars(errChannel, ENCODING_ERROR, -1); - } + Tcl_WriteObj(errChannel, Tcl_GetVar2Ex(interp, + "errorInfo", NULL, TCL_GLOBAL_ONLY)); Tcl_WriteChars(errChannel, "\n", -1); } else { Tcl_DiscardInterpState(saved); - Tcl_WriteChars(errChannel, "bgerror failed to handle" - " background error.\n Original error: ", -1); - if (Tcl_WriteObj(errChannel, tempObjv[1]) < 0) { - Tcl_WriteChars(errChannel, ENCODING_ERROR, -1); - } - Tcl_WriteChars(errChannel, "\n Error in bgerror: ", -1); - if (Tcl_WriteObj(errChannel, resultPtr) < 0) { - Tcl_WriteChars(errChannel, ENCODING_ERROR, -1); - } + Tcl_WriteChars(errChannel, + "bgerror failed to handle background error.\n",-1); + Tcl_WriteChars(errChannel, " Original error: ", -1); + Tcl_WriteObj(errChannel, tempObjv[1]); + Tcl_WriteChars(errChannel, "\n", -1); + Tcl_WriteChars(errChannel, " Error in bgerror: ", -1); + Tcl_WriteObj(errChannel, resultPtr); Tcl_WriteChars(errChannel, "\n", -1); } Tcl_DecrRefCount(resultPtr); @@ -546,7 +498,8 @@ TclSetBgErrorHandler( Tcl_Interp *interp, Tcl_Obj *cmdPrefix) { - ErrAssocData *assocPtr = (ErrAssocData *)Tcl_GetAssocData(interp, "tclBgError", NULL); + ErrAssocData *assocPtr = (ErrAssocData *) + Tcl_GetAssocData(interp, "tclBgError", NULL); if (cmdPrefix == NULL) { Tcl_Panic("TclSetBgErrorHandler: NULL cmdPrefix argument"); @@ -556,12 +509,13 @@ TclSetBgErrorHandler( * First access: initialize. */ - assocPtr = (ErrAssocData*)ckalloc(sizeof(ErrAssocData)); + assocPtr = (ErrAssocData *) ckalloc(sizeof(ErrAssocData)); assocPtr->interp = interp; assocPtr->cmdPrefix = NULL; assocPtr->firstBgPtr = NULL; assocPtr->lastBgPtr = NULL; - Tcl_SetAssocData(interp, "tclBgError", BgErrorDeleteProc, assocPtr); + Tcl_SetAssocData(interp, "tclBgError", BgErrorDeleteProc, + (ClientData) assocPtr); } if (assocPtr->cmdPrefix) { Tcl_DecrRefCount(assocPtr->cmdPrefix); @@ -591,14 +545,16 @@ Tcl_Obj * TclGetBgErrorHandler( Tcl_Interp *interp) { - ErrAssocData *assocPtr = (ErrAssocData *)Tcl_GetAssocData(interp, "tclBgError", NULL); + ErrAssocData *assocPtr = (ErrAssocData *) + Tcl_GetAssocData(interp, "tclBgError", NULL); if (assocPtr == NULL) { Tcl_Obj *bgerrorObj; TclNewLiteralStringObj(bgerrorObj, "::tcl::Bgerror"); TclSetBgErrorHandler(interp, bgerrorObj); - assocPtr = (ErrAssocData *)Tcl_GetAssocData(interp, "tclBgError", NULL); + assocPtr = (ErrAssocData *) + Tcl_GetAssocData(interp, "tclBgError", NULL); } return assocPtr->cmdPrefix; } @@ -610,24 +566,24 @@ TclGetBgErrorHandler( * * This function is associated with the "tclBgError" assoc data for an * interpreter; it is invoked when the interpreter is deleted in order to - * free the information associated with any pending error reports. + * free the information assoicated with any pending error reports. * * Results: * None. * * Side effects: * Background error information is freed: if there were any pending error - * reports, they are canceled. + * reports, they are cancelled. * *---------------------------------------------------------------------- */ static void BgErrorDeleteProc( - void *clientData, /* Pointer to ErrAssocData structure. */ - TCL_UNUSED(Tcl_Interp *)) + ClientData clientData, /* Pointer to ErrAssocData structure. */ + Tcl_Interp *interp) /* Interpreter being deleted. */ { - ErrAssocData *assocPtr = (ErrAssocData *)clientData; + ErrAssocData *assocPtr = (ErrAssocData *) clientData; BgError *errPtr; while (assocPtr->firstBgPtr != NULL) { @@ -635,11 +591,11 @@ BgErrorDeleteProc( assocPtr->firstBgPtr = errPtr->nextPtr; Tcl_DecrRefCount(errPtr->errorMsg); Tcl_DecrRefCount(errPtr->returnOpts); - ckfree(errPtr); + ckfree((char *) errPtr); } - Tcl_CancelIdleCall(HandleBgErrors, assocPtr); + Tcl_CancelIdleCall(HandleBgErrors, (ClientData) assocPtr); Tcl_DecrRefCount(assocPtr->cmdPrefix); - Tcl_EventuallyFree(assocPtr, TCL_DYNAMIC); + Tcl_EventuallyFree((ClientData) assocPtr, TCL_DYNAMIC); } /* @@ -663,10 +619,11 @@ BgErrorDeleteProc( void Tcl_CreateExitHandler( Tcl_ExitProc *proc, /* Function to invoke. */ - void *clientData) /* Arbitrary value to pass to proc. */ + ClientData clientData) /* Arbitrary value to pass to proc. */ { - ExitHandler *exitPtr = (ExitHandler*)ckalloc(sizeof(ExitHandler)); + ExitHandler *exitPtr; + exitPtr = (ExitHandler *) ckalloc(sizeof(ExitHandler)); exitPtr->proc = proc; exitPtr->clientData = clientData; Tcl_MutexLock(&exitMutex); @@ -680,8 +637,7 @@ Tcl_CreateExitHandler( * * TclCreateLateExitHandler -- * - * Arrange for a given function to be invoked after all pre-thread - * cleanups. + * Arrange for a given function to be invoked after all pre-thread cleanups * * Results: * None. @@ -696,10 +652,11 @@ Tcl_CreateExitHandler( void TclCreateLateExitHandler( Tcl_ExitProc *proc, /* Function to invoke. */ - void *clientData) /* Arbitrary value to pass to proc. */ + ClientData clientData) /* Arbitrary value to pass to proc. */ { - ExitHandler *exitPtr = (ExitHandler*)ckalloc(sizeof(ExitHandler)); + ExitHandler *exitPtr; + exitPtr = (ExitHandler *) ckalloc(sizeof(ExitHandler)); exitPtr->proc = proc; exitPtr->clientData = clientData; Tcl_MutexLock(&exitMutex); @@ -721,7 +678,7 @@ TclCreateLateExitHandler( * * Side effects: * If there is an exit handler corresponding to proc and clientData then - * it is canceled; if no such handler exists then nothing happens. + * it is cancelled; if no such handler exists then nothing happens. * *---------------------------------------------------------------------- */ @@ -729,7 +686,7 @@ TclCreateLateExitHandler( void Tcl_DeleteExitHandler( Tcl_ExitProc *proc, /* Function that was previously registered. */ - void *clientData) /* Arbitrary value to pass to proc. */ + ClientData clientData) /* Arbitrary value to pass to proc. */ { ExitHandler *exitPtr, *prevPtr; @@ -743,7 +700,7 @@ Tcl_DeleteExitHandler( } else { prevPtr->nextPtr = exitPtr->nextPtr; } - ckfree(exitPtr); + ckfree((char *) exitPtr); break; } } @@ -763,8 +720,8 @@ Tcl_DeleteExitHandler( * None. * * Side effects: - * If there is a late exit handler corresponding to proc and clientData - * then it is canceled; if no such handler exists then nothing happens. + * If there is a late exit handler corresponding to proc and clientData then + * it is canceled; if no such handler exists then nothing happens. * *---------------------------------------------------------------------- */ @@ -772,7 +729,7 @@ Tcl_DeleteExitHandler( void TclDeleteLateExitHandler( Tcl_ExitProc *proc, /* Function that was previously registered. */ - void *clientData) /* Arbitrary value to pass to proc. */ + ClientData clientData) /* Arbitrary value to pass to proc. */ { ExitHandler *exitPtr, *prevPtr; @@ -786,7 +743,7 @@ TclDeleteLateExitHandler( } else { prevPtr->nextPtr = exitPtr->nextPtr; } - ckfree(exitPtr); + ckfree((char *) exitPtr); break; } } @@ -815,12 +772,12 @@ TclDeleteLateExitHandler( void Tcl_CreateThreadExitHandler( Tcl_ExitProc *proc, /* Function to invoke. */ - void *clientData) /* Arbitrary value to pass to proc. */ + ClientData clientData) /* Arbitrary value to pass to proc. */ { ExitHandler *exitPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - exitPtr = (ExitHandler*)ckalloc(sizeof(ExitHandler)); + exitPtr = (ExitHandler *) ckalloc(sizeof(ExitHandler)); exitPtr->proc = proc; exitPtr->clientData = clientData; exitPtr->nextPtr = tsdPtr->firstExitPtr; @@ -840,7 +797,7 @@ Tcl_CreateThreadExitHandler( * * Side effects: * If there is an exit handler corresponding to proc and clientData then - * it is canceled; if no such handler exists then nothing happens. + * it is cancelled; if no such handler exists then nothing happens. * *---------------------------------------------------------------------- */ @@ -848,7 +805,7 @@ Tcl_CreateThreadExitHandler( void Tcl_DeleteThreadExitHandler( Tcl_ExitProc *proc, /* Function that was previously registered. */ - void *clientData) /* Arbitrary value to pass to proc. */ + ClientData clientData) /* Arbitrary value to pass to proc. */ { ExitHandler *exitPtr, *prevPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); @@ -862,7 +819,7 @@ Tcl_DeleteThreadExitHandler( } else { prevPtr->nextPtr = exitPtr->nextPtr; } - ckfree(exitPtr); + ckfree((char *) exitPtr); return; } } @@ -888,7 +845,7 @@ Tcl_DeleteThreadExitHandler( Tcl_ExitProc * Tcl_SetExitProc( - TCL_NORETURN1 Tcl_ExitProc *proc) /* New exit handler for app or NULL */ + Tcl_ExitProc *proc) /* New exit handler for app or NULL */ { Tcl_ExitProc *prevExitProc; @@ -904,49 +861,6 @@ Tcl_SetExitProc( return prevExitProc; } - - -/* - *---------------------------------------------------------------------- - * - * InvokeExitHandlers -- - * - * Call the registered exit handlers. - * - * Results: - * None. - * - * Side effects: - * The exit handlers are invoked, and the ExitHandler struct is - * freed. - * - *---------------------------------------------------------------------- - */ -static void -InvokeExitHandlers(void) -{ - ExitHandler *exitPtr; - - Tcl_MutexLock(&exitMutex); - inExit = 1; - - for (exitPtr = firstExitPtr; exitPtr != NULL; exitPtr = firstExitPtr) { - /* - * Be careful to remove the handler from the list before invoking its - * callback. This protects us against double-freeing if the callback - * should call Tcl_DeleteExitHandler on itself. - */ - - firstExitPtr = exitPtr->nextPtr; - Tcl_MutexUnlock(&exitMutex); - exitPtr->proc(exitPtr->clientData); - ckfree(exitPtr); - Tcl_MutexLock(&exitMutex); - } - firstExitPtr = NULL; - Tcl_MutexUnlock(&exitMutex); -} - /* *---------------------------------------------------------------------- @@ -964,73 +878,41 @@ InvokeExitHandlers(void) *---------------------------------------------------------------------- */ -TCL_NORETURN void +void Tcl_Exit( int status) /* Exit status for application; typically 0 * for normal return, 1 for error return. */ { - TCL_NORETURN1 Tcl_ExitProc *currentAppExitPtr; + Tcl_ExitProc *currentAppExitPtr; Tcl_MutexLock(&exitMutex); currentAppExitPtr = appExitPtr; Tcl_MutexUnlock(&exitMutex); - /* - * Warning: this function SHOULD NOT return, as there is code that depends - * on Tcl_Exit never returning. In fact, we will Tcl_Panic if anyone - * returns, so critical is this dependency. - * - * If subsystems are not (yet) initialized, proper Tcl-finalization is - * impossible, so fallback to system exit, see bug-[f8a33ce3db5d8cc2]. - */ - if (currentAppExitPtr) { + /* + * Warning: this code SHOULD NOT return, as there is code that depends + * on Tcl_Exit never returning. In fact, we will Tcl_Panic if anyone + * returns, so critical is this dependcy. + */ - currentAppExitPtr(INT2PTR(status)); - - } else if (subsystemsInitialized) { - - if (TclFullFinalizationRequested()) { - - /* - * Thorough finalization for Valgrind et al. - */ - - Tcl_Finalize(); - - } else { - - /* - * Fast and deterministic exit (default behavior) - */ - - InvokeExitHandlers(); - - /* - * Ensure the thread-specific data is initialised as it is used in - * Tcl_FinalizeThread() - */ - - (void) TCL_TSD_INIT(&dataKey); - - /* - * Now finalize the calling thread only (others are not safely - * reachable). Among other things, this triggers a flush of the - * Tcl_Channels that may have data enqueued. - */ + currentAppExitPtr((ClientData) INT2PTR(status)); + Tcl_Panic("AppExitProc returned unexpectedly"); + } else { + /* + * Use default handling. + */ - FinalizeThread(/* quick */ 1); - } + Tcl_Finalize(); + TclpExit(status); + Tcl_Panic("OS exit failed!"); } - - TclpExit(status); - Tcl_Panic("OS exit failed!"); } /* *------------------------------------------------------------------------- * - * Tcl_InitSubsystems -- + * TclInitSubsystems -- * * Initialize various subsytems in Tcl. This should be called the first * time an interp is created, or before any of the subsystems are used. @@ -1044,7 +926,7 @@ Tcl_Exit( * down another. * * Results: - * The full Tcl version with build information. + * None. * * Side effects: * Varied, see the respective initialization routines. @@ -1052,95 +934,16 @@ Tcl_Exit( *------------------------------------------------------------------------- */ -MODULE_SCOPE const TclStubs tclStubs; - -#ifndef STRINGIFY -# define STRINGIFY(x) STRINGIFY1(x) -# define STRINGIFY1(x) #x -#endif - -static const struct { - const TclStubs *stubs; - const char version[256]; -} stubInfo = { - &tclStubs, {TCL_PATCH_LEVEL "+" STRINGIFY(TCL_VERSION_UUID) -#if defined(__clang__) && defined(__clang_major__) - ".clang-" STRINGIFY(__clang_major__) -#if __clang_minor__ < 10 - "0" -#endif - STRINGIFY(__clang_minor__) -#endif -#ifdef TCL_COMPILE_DEBUG - ".compiledebug" -#endif -#ifdef TCL_COMPILE_STATS - ".compilestats" -#endif -#if defined(__cplusplus) && !defined(__OBJC__) - ".cplusplus" -#endif -#ifndef NDEBUG - ".debug" -#endif -#if !defined(__clang__) && !defined(__INTEL_COMPILER) && defined(__GNUC__) - ".gcc-" STRINGIFY(__GNUC__) -#if __GNUC_MINOR__ < 10 - "0" -#endif - STRINGIFY(__GNUC_MINOR__) -#endif -#ifdef __INTEL_COMPILER - ".icc-" STRINGIFY(__INTEL_COMPILER) -#endif -#if (defined(_WIN32) || (ULONG_MAX == 0xffffffffUL)) && !defined(_WIN64) - ".ilp32" -#endif -#ifdef TCL_MEM_DEBUG - ".memdebug" -#endif -#if defined(_MSC_VER) - ".msvc-" STRINGIFY(_MSC_VER) -#endif -#ifdef USE_NMAKE - ".nmake" -#endif -#ifdef TCL_NO_DEPRECATED - ".no-deprecate" -#endif -#if !TCL_THREADS - ".no-thread" -#endif -#ifndef TCL_CFG_OPTIMIZED - ".no-optimize" -#endif -#ifdef __OBJC__ - ".objective-c" -#if defined(__cplusplus) - "plusplus" -#endif -#endif -#ifdef TCL_CFG_PROFILED - ".profile" -#endif -#ifdef PURIFY - ".purify" -#endif -#ifdef STATIC_BUILD - ".static" -#endif -}}; - -const char * -Tcl_InitSubsystems(void) +void +TclInitSubsystems(void) { - if (inExit != 0) { - Tcl_Panic("Tcl_InitSubsystems called while exiting"); + if (inFinalize != 0) { + Tcl_Panic("TclInitSubsystems called while finalizing"); } if (subsystemsInitialized == 0) { /* - * Double check inside the mutex. There are definitely calls back into + * Double check inside the mutex. There are definitly calls back into * this routine from some of the functions below. */ @@ -1153,14 +956,11 @@ Tcl_InitSubsystems(void) * implementation of self-initializing locks. */ - TclInitThreadStorage(); /* Creates hash table for + TclInitThreadStorage(); /* Creates master hash table for * thread local storage */ -#if defined(USE_TCLALLOC) && USE_TCLALLOC +#if USE_TCLALLOC TclInitAlloc(); /* Process wide mutex init */ #endif -#if TCL_THREADS && defined(USE_THREAD_ALLOC) - TclInitThreadAlloc(); /* Setup thread allocator caches */ -#endif #ifdef TCL_MEM_DEBUG TclInitDbCkalloc(); /* Process wide mutex init */ #endif @@ -1172,13 +972,13 @@ Tcl_InitSubsystems(void) * mutexes. */ TclInitIOSubsystem(); /* Inits a tsd key (noop). */ TclInitEncodingSubsystem(); /* Process wide encoding init. */ + TclpSetInterfaces(); TclInitNamespaceSubsystem();/* Register ns obj type (mutexed). */ subsystemsInitialized = 1; } TclpInitUnlock(); } TclInitNotifier(); - return stubInfo.version; } /* @@ -1187,8 +987,8 @@ Tcl_InitSubsystems(void) * Tcl_Finalize -- * * Shut down Tcl. First calls registered exit handlers, then carefully - * shuts down various subsystems. Should be invoked by user before the - * Tcl shared library is being unloaded in an embedded context. + * shuts down various subsystems. Called by Tcl_Exit or when the Tcl + * shared library is being unloaded. * * Results: * None. @@ -1208,7 +1008,23 @@ Tcl_Finalize(void) * Invoke exit handlers first. */ - InvokeExitHandlers(); + Tcl_MutexLock(&exitMutex); + inFinalize = 1; + for (exitPtr = firstExitPtr; exitPtr != NULL; exitPtr = firstExitPtr) { + /* + * Be careful to remove the handler from the list before invoking its + * callback. This protects us against double-freeing if the callback + * should call Tcl_DeleteExitHandler on itself. + */ + + firstExitPtr = exitPtr->nextPtr; + Tcl_MutexUnlock(&exitMutex); + (*exitPtr->proc)(exitPtr->clientData); + ckfree((char *) exitPtr); + Tcl_MutexLock(&exitMutex); + } + firstExitPtr = NULL; + Tcl_MutexUnlock(&exitMutex); TclpInitLock(); if (subsystemsInitialized == 0) { @@ -1237,8 +1053,7 @@ Tcl_Finalize(void) */ Tcl_MutexLock(&exitMutex); - for (exitPtr = firstLateExitPtr; exitPtr != NULL; - exitPtr = firstLateExitPtr) { + for (exitPtr = firstLateExitPtr; exitPtr != NULL; exitPtr = firstLateExitPtr) { /* * Be careful to remove the handler from the list before invoking its * callback. This protects us against double-freeing if the callback @@ -1248,7 +1063,7 @@ Tcl_Finalize(void) firstLateExitPtr = exitPtr->nextPtr; Tcl_MutexUnlock(&exitMutex); exitPtr->proc(exitPtr->clientData); - ckfree(exitPtr); + ckfree((char *) exitPtr); Tcl_MutexLock(&exitMutex); } firstLateExitPtr = NULL; @@ -1259,7 +1074,6 @@ Tcl_Finalize(void) * after the exit handlers, because there are order dependencies. */ - TclFinalizeEvaluation(); TclFinalizeExecution(); TclFinalizeEnvironment(); @@ -1271,7 +1085,7 @@ Tcl_Finalize(void) TclFinalizeFilesystem(); /* - * Undo all Tcl_ObjType registrations, and reset the global list of free + * Undo all Tcl_ObjType registrations, and reset the master list of free * Tcl_Obj's. After this returns, no more Tcl_Obj's should be allocated or * freed. * @@ -1290,6 +1104,8 @@ Tcl_Finalize(void) TclFinalizeEncodingSubsystem(); + Tcl_SetPanicProc(NULL); + /* * Repeat finalization of the thread local storage once more. Although * this step is already done by the Tcl_FinalizeThread call above, series @@ -1302,7 +1118,7 @@ Tcl_Finalize(void) * This fixes the Tcl Bug #990552. */ - TclFinalizeThreadData(/* quick */ 0); + TclFinalizeThreadData(); /* * Now we can free constants for conversions to/from double. @@ -1313,10 +1129,10 @@ Tcl_Finalize(void) /* * There have been several bugs in the past that cause exit handlers to be * established during Tcl_Finalize processing. Such exit handlers leave - * malloc'ed memory, and Tcl_FinalizeMemorySubsystem or - * Tcl_FinalizeThreadAlloc will result in a corrupted heap. The result can - * be a mysterious crash on process exit. Check here that nobody's done - * this. + * malloc'ed memory, and Tcl_FinalizeThreadAlloc or + * Tcl_FinalizeMemorySubsystem will result in a corrupted heap. The result + * can be a mysterious crash on process exit. Check here that nobody's + * done this. */ if (firstExitPtr != NULL) { @@ -1336,7 +1152,7 @@ Tcl_Finalize(void) * Close down the thread-specific object allocator. */ -#if TCL_THREADS && defined(USE_THREAD_ALLOC) +#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) TclFinalizeThreadAlloc(); #endif @@ -1363,6 +1179,7 @@ Tcl_Finalize(void) */ TclFinalizeMemorySubsystem(); + inFinalize = 0; alreadyFinalized: TclFinalizeLock(); @@ -1388,13 +1205,6 @@ Tcl_Finalize(void) void Tcl_FinalizeThread(void) { - FinalizeThread(/* quick */ 0); -} - -void -FinalizeThread( - int quick) -{ ExitHandler *exitPtr; ThreadSpecificData *tsdPtr; @@ -1404,7 +1214,7 @@ FinalizeThread( * initialized already. */ - tsdPtr = (ThreadSpecificData*)TclThreadDataKeyGet(&dataKey); + tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (tsdPtr != NULL) { tsdPtr->inExit = 1; @@ -1417,8 +1227,8 @@ FinalizeThread( */ tsdPtr->firstExitPtr = exitPtr->nextPtr; - exitPtr->proc(exitPtr->clientData); - ckfree(exitPtr); + (*exitPtr->proc)(exitPtr->clientData); + ckfree((char *) exitPtr); } TclFinalizeIOSubsystem(); TclFinalizeNotifier(); @@ -1435,7 +1245,8 @@ FinalizeThread( * * Fix [Bug #571002] */ - TclFinalizeThreadData(quick); + + TclFinalizeThreadData(); } /* @@ -1457,7 +1268,7 @@ FinalizeThread( int TclInExit(void) { - return inExit; + return inFinalize; } /* @@ -1479,12 +1290,13 @@ TclInExit(void) int TclInThreadExit(void) { - ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); - + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + TclThreadDataKeyGet(&dataKey); if (tsdPtr == NULL) { return 0; + } else { + return tsdPtr->inExit; } - return tsdPtr->inExit; } /* @@ -1504,439 +1316,69 @@ TclInThreadExit(void) *---------------------------------------------------------------------- */ + /* ARGSUSED */ int Tcl_VwaitObjCmd( - TCL_UNUSED(void *), + ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ - Tcl_Obj *const objv[]) /* Argument objects. */ + Tcl_Obj *CONST objv[]) /* Argument objects. */ { - int i, done = 0, timedOut = 0, foundEvent, any = 1, timeout = 0; - int numItems = 0, extended = 0, result, mode, mask = TCL_ALL_EVENTS; - Tcl_InterpState saved = NULL; - Tcl_TimerToken timer = NULL; - Tcl_Time before, after; - Tcl_Channel chan; - Tcl_WideInt diff = -1; - VwaitItem localItems[32], *vwaitItems = localItems; - static const char *const vWaitOptionStrings[] = { - "-all", "-extended", "-nofileevents", "-noidleevents", - "-notimerevents", "-nowindowevents", "-readable", - "-timeout", "-variable", "-writable", "--", NULL - }; - enum vWaitOptions { - OPT_ALL, OPT_EXTD, OPT_NO_FEVTS, OPT_NO_IEVTS, - OPT_NO_TEVTS, OPT_NO_WEVTS, OPT_READABLE, - OPT_TIMEOUT, OPT_VARIABLE, OPT_WRITABLE, OPT_LAST - } index; - - if ((objc == 2) && (strcmp(TclGetString(objv[1]), "--") != 0)) { - /* - * Legacy "vwait" syntax, skip option handling. - */ - i = 1; - goto endOfOptionLoop; - } - - if ((unsigned) objc - 1 > sizeof(localItems) / sizeof(localItems[0])) { - vwaitItems = (VwaitItem *) ckalloc(sizeof(VwaitItem) * (objc - 1)); - } + int done, foundEvent; + char *nameString; - for (i = 1; i < objc; i++) { - const char *name; - - name = TclGetString(objv[i]); - if (name[0] != '-') { - break; - } - if (Tcl_GetIndexFromObj(interp, objv[i], vWaitOptionStrings, "option", 0, - &index) != TCL_OK) { - result = TCL_ERROR; - goto done; - } - switch (index) { - case OPT_ALL: - any = 0; - break; - case OPT_EXTD: - extended = 1; - break; - case OPT_NO_FEVTS: - mask &= ~TCL_FILE_EVENTS; - break; - case OPT_NO_IEVTS: - mask &= ~TCL_IDLE_EVENTS; - break; - case OPT_NO_TEVTS: - mask &= ~TCL_TIMER_EVENTS; - break; - case OPT_NO_WEVTS: - mask &= ~TCL_WINDOW_EVENTS; - break; - case OPT_TIMEOUT: - if (++i >= objc) { - needArg: - Tcl_ResetResult(interp); - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "argument required for \"%s\"", vWaitOptionStrings[index])); - Tcl_SetErrorCode(interp, "TCL", "EVENT", "ARGUMENT", (void *)NULL); - result = TCL_ERROR; - goto done; - } - if (Tcl_GetIntFromObj(interp, objv[i], &timeout) != TCL_OK) { - result = TCL_ERROR; - goto done; - } - if (timeout < 0) { - Tcl_ResetResult(interp); - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "timeout must be positive", -1)); - Tcl_SetErrorCode(interp, "TCL", "EVENT", "NEGTIME", (void *)NULL); - result = TCL_ERROR; - goto done; - } - break; - case OPT_LAST: - i++; - goto endOfOptionLoop; - case OPT_VARIABLE: - if (++i >= objc) { - goto needArg; - } - result = Tcl_TraceVar2(interp, TclGetString(objv[i]), NULL, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - VwaitVarProc, &vwaitItems[numItems]); - if (result != TCL_OK) { - goto done; - } - vwaitItems[numItems].donePtr = &done; - vwaitItems[numItems].sequence = -1; - vwaitItems[numItems].mask = 0; - vwaitItems[numItems].sourceObj = objv[i]; - numItems++; - break; - case OPT_READABLE: - if (++i >= objc) { - goto needArg; - } - if (TclGetChannelFromObj(interp, objv[i], &chan, &mode, 0) - != TCL_OK) { - result = TCL_ERROR; - goto done; - } - if (!(mode & TCL_READABLE)) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "channel \"%s\" wasn't open for reading", - TclGetString(objv[i]))); - result = TCL_ERROR; - goto done; - } - Tcl_CreateChannelHandler(chan, TCL_READABLE, - VwaitChannelReadProc, &vwaitItems[numItems]); - vwaitItems[numItems].donePtr = &done; - vwaitItems[numItems].sequence = -1; - vwaitItems[numItems].mask = TCL_READABLE; - vwaitItems[numItems].sourceObj = objv[i]; - numItems++; - break; - case OPT_WRITABLE: - if (++i >= objc) { - goto needArg; - } - if (TclGetChannelFromObj(interp, objv[i], &chan, &mode, 0) - != TCL_OK) { - result = TCL_ERROR; - goto done; - } - if (!(mode & TCL_WRITABLE)) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "channel \"%s\" wasn't open for writing", - TclGetString(objv[i]))); - result = TCL_ERROR; - goto done; - } - Tcl_CreateChannelHandler(chan, TCL_WRITABLE, - VwaitChannelWriteProc, &vwaitItems[numItems]); - vwaitItems[numItems].donePtr = &done; - vwaitItems[numItems].sequence = -1; - vwaitItems[numItems].mask = TCL_WRITABLE; - vwaitItems[numItems].sourceObj = objv[i]; - numItems++; - break; - } - } - - endOfOptionLoop: - if ((mask & (TCL_FILE_EVENTS | TCL_IDLE_EVENTS | - TCL_TIMER_EVENTS | TCL_WINDOW_EVENTS)) == 0) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "can't wait: would block forever", -1)); - Tcl_SetErrorCode(interp, "TCL", "EVENT", "NO_SOURCES", (void *)NULL); - result = TCL_ERROR; - goto done; - } - - if ((timeout > 0) && ((mask & TCL_TIMER_EVENTS) == 0)) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "timer events disabled with timeout specified", -1)); - Tcl_SetErrorCode(interp, "TCL", "EVENT", "NO_TIME", (void *)NULL); - result = TCL_ERROR; - goto done; - } - - for (result = TCL_OK; i < objc; i++) { - result = Tcl_TraceVar2(interp, TclGetString(objv[i]), NULL, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - VwaitVarProc, &vwaitItems[numItems]); - if (result != TCL_OK) { - break; - } - vwaitItems[numItems].donePtr = &done; - vwaitItems[numItems].sequence = -1; - vwaitItems[numItems].mask = 0; - vwaitItems[numItems].sourceObj = objv[i]; - numItems++; - } - if (result != TCL_OK) { - result = TCL_ERROR; - goto done; - } - - if (!(mask & TCL_FILE_EVENTS)) { - for (i = 0; i < numItems; i++) { - if (vwaitItems[i].mask) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "file events disabled with channel(s) specified", -1)); - Tcl_SetErrorCode(interp, "TCL", "EVENT", "NO_FILE_EVENT", (void *)NULL); - result = TCL_ERROR; - goto done; - } - } - } - - if (timeout > 0) { - vwaitItems[numItems].donePtr = &timedOut; - vwaitItems[numItems].sequence = -1; - vwaitItems[numItems].mask = 0; - vwaitItems[numItems].sourceObj = NULL; - timer = Tcl_CreateTimerHandler(timeout, VwaitTimeoutProc, - &vwaitItems[numItems]); - Tcl_GetTime(&before); - } else { - timeout = 0; - } - - if ((numItems == 0) && (timeout == 0)) { - /* - * "vwait" is equivalent to "update", - * "vwait -nofileevents -notimerevents -nowindowevents" - * is equivalent to "update idletasks" - */ - any = 1; - mask |= TCL_DONT_WAIT; + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; } - + nameString = Tcl_GetString(objv[1]); + if (Tcl_TraceVar(interp, nameString, + TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, + VwaitVarProc, (ClientData) &done) != TCL_OK) { + return TCL_ERROR; + }; + done = 0; foundEvent = 1; - while (!timedOut && foundEvent && - ((!any && (done < numItems)) || (any && !done))) { - foundEvent = Tcl_DoOneEvent(mask); - if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) { - break; - } + while (!done && foundEvent) { + foundEvent = Tcl_DoOneEvent(TCL_ALL_EVENTS); if (Tcl_LimitExceeded(interp)) { - Tcl_ResetResult(interp); - Tcl_SetObjResult(interp, Tcl_NewStringObj("limit exceeded", -1)); - Tcl_SetErrorCode(interp, "TCL", "EVENT", "LIMIT", (void *)NULL); break; } - if ((numItems == 0) && (timeout == 0)) { - /* - * Behavior like "update": clear interpreter's result because - * event handlers could have executed commands. - */ - Tcl_ResetResult(interp); - result = TCL_OK; - goto done; - } - } - - if (!foundEvent) { - Tcl_ResetResult(interp); - Tcl_SetObjResult(interp, Tcl_NewStringObj((numItems == 0) ? - "can't wait: would wait forever" : - "can't wait for variable(s)/channel(s): would wait forever", - -1)); - Tcl_SetErrorCode(interp, "TCL", "EVENT", "NO_SOURCES", (void *)NULL); - result = TCL_ERROR; - goto done; - } - - if (!done && !timedOut) { - /* - * The interpreter's result was already set to the right error message - * prior to exiting the loop above. - */ - result = TCL_ERROR; - goto done; - } - - result = TCL_OK; - if (timeout <= 0) { - /* - * Clear out the interpreter's result, since it may have been set - * by event handlers. - */ - Tcl_ResetResult(interp); - goto done; } + Tcl_UntraceVar(interp, nameString, + TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, + VwaitVarProc, (ClientData) &done); /* - * When timeout was specified, report milliseconds left or -1 on timeout. + * Clear out the interpreter's result, since it may have been set by event + * handlers. */ - if (timedOut) { - diff = -1; - } else { - Tcl_GetTime(&after); - diff = after.sec * 1000 + after.usec / 1000; - diff -= before.sec * 1000 + before.usec / 1000; - diff = timeout - diff; - if (diff < 0) { - diff = 0; - } - } - - done: - if ((timeout > 0) && (timer != NULL)) { - Tcl_DeleteTimerHandler(timer); - } - if (result != TCL_OK) { - saved = Tcl_SaveInterpState(interp, result); - } - for (i = 0; i < numItems; i++) { - if (vwaitItems[i].mask & TCL_READABLE) { - if (TclGetChannelFromObj(interp, vwaitItems[i].sourceObj, - &chan, &mode, 0) == TCL_OK) { - Tcl_DeleteChannelHandler(chan, VwaitChannelReadProc, - &vwaitItems[i]); - } - } else if (vwaitItems[i].mask & TCL_WRITABLE) { - if (TclGetChannelFromObj(interp, vwaitItems[i].sourceObj, - &chan, &mode, 0) == TCL_OK) { - Tcl_DeleteChannelHandler(chan, VwaitChannelWriteProc, - &vwaitItems[i]); - } - } else { - Tcl_UntraceVar2(interp, TclGetString(vwaitItems[i].sourceObj), - NULL, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - VwaitVarProc, &vwaitItems[i]); - } - } - - if (result == TCL_OK) { - if (extended) { - int k; - Tcl_Obj *listObj, *keyObj; - - TclNewObj(listObj); - for (k = 0; k < done; k++) { - for (i = 0; i < numItems; i++) { - if (vwaitItems[i].sequence != k) { - continue; - } - if (vwaitItems[i].mask & TCL_READABLE) { - TclNewLiteralStringObj(keyObj, "readable"); - } else if (vwaitItems[i].mask & TCL_WRITABLE) { - TclNewLiteralStringObj(keyObj, "writable"); - } else { - TclNewLiteralStringObj(keyObj, "variable"); - } - Tcl_ListObjAppendElement(NULL, listObj, keyObj); - Tcl_ListObjAppendElement(NULL, listObj, - vwaitItems[i].sourceObj); - } - } - if (timeout > 0) { - TclNewLiteralStringObj(keyObj, "timeleft"); - Tcl_ListObjAppendElement(NULL, listObj, keyObj); - Tcl_ListObjAppendElement(NULL, listObj, - Tcl_NewWideIntObj(diff)); - } - Tcl_SetObjResult(interp, listObj); - } else if (timeout > 0) { - Tcl_SetObjResult(interp, Tcl_NewWideIntObj(diff)); - } - } else { - result = Tcl_RestoreInterpState(interp, saved); - } - if (vwaitItems != localItems) { - ckfree(vwaitItems); - } - return result; -} - -static void -VwaitChannelReadProc( - void *clientData, /* Pointer to vwait info record. */ - int mask) /* Event mask, must be TCL_READABLE. */ -{ - VwaitItem *itemPtr = (VwaitItem *) clientData; - - if (!(mask & TCL_READABLE)) { - return; - } - if (itemPtr->donePtr != NULL) { - itemPtr->sequence = itemPtr->donePtr[0]; - itemPtr->donePtr[0] += 1; - itemPtr->donePtr = NULL; - } -} -static void -VwaitChannelWriteProc( - void *clientData, /* Pointer to vwait info record. */ - int mask) /* Event mask, must be TCL_WRITABLE. */ -{ - VwaitItem *itemPtr = (VwaitItem *) clientData; - - if (!(mask & TCL_WRITABLE)) { - return; - } - if (itemPtr->donePtr != NULL) { - itemPtr->sequence = itemPtr->donePtr[0]; - itemPtr->donePtr[0] += 1; - itemPtr->donePtr = NULL; + Tcl_ResetResult(interp); + if (!foundEvent) { + Tcl_AppendResult(interp, "can't wait for variable \"", nameString, + "\": would wait forever", NULL); + return TCL_ERROR; } -} - -static void -VwaitTimeoutProc( - void *clientData) /* Pointer to vwait info record. */ -{ - VwaitItem *itemPtr = (VwaitItem *) clientData; - - if (itemPtr->donePtr != NULL) { - itemPtr->donePtr[0] = 1; - itemPtr->donePtr = NULL; + if (!done) { + Tcl_AppendResult(interp, "limit exceeded", NULL); + return TCL_ERROR; } + return TCL_OK; } + /* ARGSUSED */ static char * VwaitVarProc( - void *clientData, /* Pointer to vwait info record. */ + ClientData clientData, /* Pointer to integer to set to 1. */ Tcl_Interp *interp, /* Interpreter containing variable. */ - const char *name1, /* Name of variable. */ - const char *name2, /* Second part of variable name. */ - TCL_UNUSED(int) /*flags*/) /* Information about what happened. */ + CONST char *name1, /* Name of variable. */ + CONST char *name2, /* Second part of variable name. */ + int flags) /* Information about what happened. */ { - VwaitItem *itemPtr = (VwaitItem *) clientData; + int *donePtr = (int *) clientData; - if (itemPtr->donePtr != NULL) { - itemPtr->sequence = itemPtr->donePtr[0]; - itemPtr->donePtr[0] += 1; - itemPtr->donePtr = NULL; - } - Tcl_UntraceVar2(interp, name1, name2, TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - VwaitVarProc, clientData); + *donePtr = 1; return NULL; } @@ -1957,17 +1399,18 @@ VwaitVarProc( *---------------------------------------------------------------------- */ + /* ARGSUSED */ int Tcl_UpdateObjCmd( - TCL_UNUSED(void *), + ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ - Tcl_Obj *const objv[]) /* Argument objects. */ + Tcl_Obj *CONST objv[]) /* Argument objects. */ { - int flags = 0; /* Initialized to avoid compiler warning. */ - static const char *const updateOptions[] = {"idletasks", NULL}; - enum updateOptionsEnum {OPT_IDLETASKS}; int optionIndex; + int flags = 0; /* Initialized to avoid compiler warning. */ + static CONST char *updateOptions[] = {"idletasks", NULL}; + enum updateOptions {REGEXP_IDLETASKS}; if (objc == 1) { flags = TCL_ALL_EVENTS|TCL_DONT_WAIT; @@ -1976,9 +1419,9 @@ Tcl_UpdateObjCmd( "option", 0, &optionIndex) != TCL_OK) { return TCL_ERROR; } - switch ((enum updateOptionsEnum) optionIndex) { - case OPT_IDLETASKS: - flags = TCL_IDLE_EVENTS|TCL_DONT_WAIT; + switch ((enum updateOptions) optionIndex) { + case REGEXP_IDLETASKS: + flags = TCL_WINDOW_EVENTS|TCL_IDLE_EVENTS|TCL_DONT_WAIT; break; default: Tcl_Panic("Tcl_UpdateObjCmd: bad option index to UpdateOptions"); @@ -1989,12 +1432,9 @@ Tcl_UpdateObjCmd( } while (Tcl_DoOneEvent(flags) != 0) { - if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) { - return TCL_ERROR; - } if (Tcl_LimitExceeded(interp)) { Tcl_ResetResult(interp); - Tcl_SetObjResult(interp, Tcl_NewStringObj("limit exceeded", -1)); + Tcl_AppendResult(interp, "limit exceeded", NULL); return TCL_ERROR; } } @@ -2008,13 +1448,13 @@ Tcl_UpdateObjCmd( return TCL_OK; } -#if TCL_THREADS +#ifdef TCL_THREADS /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * NewThreadProc -- * - * Bootstrap function of a new Tcl thread. + * Bootstrap function of a new Tcl thread. * * Results: * None. @@ -2022,22 +1462,23 @@ Tcl_UpdateObjCmd( * Side Effects: * Initializes Tcl notifier for the current thread. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ static Tcl_ThreadCreateType NewThreadProc( - void *clientData) + ClientData clientData) { - ThreadClientData *cdPtr = (ThreadClientData *)clientData; - void *threadClientData; + ThreadClientData *cdPtr; + ClientData threadClientData; Tcl_ThreadCreateProc *threadProc; + cdPtr = (ThreadClientData *) clientData; threadProc = cdPtr->proc; threadClientData = cdPtr->clientData; - ckfree(clientData); /* Allocated in Tcl_CreateThread() */ + ckfree((char *) clientData); /* Allocated in Tcl_CreateThread() */ - threadProc(threadClientData); + (*threadProc)(threadClientData); TCL_THREAD_CREATE_RETURN; } @@ -2065,30 +1506,22 @@ NewThreadProc( int Tcl_CreateThread( Tcl_ThreadId *idPtr, /* Return, the ID of the thread */ - Tcl_ThreadCreateProc *proc, /* Main() function of the thread */ - void *clientData, /* The one argument to Main() */ - TCL_HASH_TYPE stackSize, /* Size of stack for the new thread */ + Tcl_ThreadCreateProc proc, /* Main() function of the thread */ + ClientData clientData, /* The one argument to Main() */ + int stackSize, /* Size of stack for the new thread */ int flags) /* Flags controlling behaviour of the new * thread. */ { -#if TCL_THREADS - ThreadClientData *cdPtr = (ThreadClientData *)ckalloc(sizeof(ThreadClientData)); - int result; +#ifdef TCL_THREADS + ThreadClientData *cdPtr; + cdPtr = (ThreadClientData *) ckalloc(sizeof(ThreadClientData)); cdPtr->proc = proc; cdPtr->clientData = clientData; - result = TclpThreadCreate(idPtr, NewThreadProc, cdPtr, stackSize, flags); - if (result != TCL_OK) { - ckfree(cdPtr); - } - return result; -#else - (void)idPtr; - (void)proc; - (void)clientData; - (void)stackSize; - (void)flags; + return TclpThreadCreate(idPtr, NewThreadProc, (ClientData) cdPtr, + stackSize, flags); +#else return TCL_ERROR; #endif /* TCL_THREADS */ } |
