From 6067cbda26bb2ab8ba3a478df836c0fd310f25f9 Mon Sep 17 00:00:00 2001 From: davygrvy Date: Mon, 30 Sep 2002 00:08:01 +0000 Subject: Added proper exiting conditions using Win32 console signals. This handles the existing lack of a Ctrl+C exit to call exit handlers when built for thread support. Also, properly handles exits from other conditions such as CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT signals. In all cases, exit handlers will be called. [Bug 219355] --- ChangeLog | 7 +++++ win/tclAppInit.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 5fba8be..ad7544e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2002-09-29 David Gravereaux + * win/tclAppInit.c: Added proper exiting conditions using Win32 + console signals. This handles the existing lack of a Ctrl+C exit + to call exit handlers when built for thread support. Also, properly + handles exits from other conditions such as CTRL_CLOSE_EVENT, + CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT signals. In all cases, + exit handlers will be called. [Bug 219355] + * win/makefile.vc: Added missing tclThreadAlloc.c to the build rules and defines USE_THREAD_ALLOC when TCL_THREADS is defined to get the new behavior by default. diff --git a/win/tclAppInit.c b/win/tclAppInit.c index 5ddc93f..414e4d8 100644 --- a/win/tclAppInit.c +++ b/win/tclAppInit.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclAppInit.c,v 1.8 2002/02/21 21:20:08 davygrvy Exp $ + * RCS: @(#) $Id: tclAppInit.c,v 1.9 2002/09/30 00:08:01 davygrvy Exp $ */ #include "tcl.h" @@ -29,6 +29,11 @@ extern int TclThread_Init _ANSI_ARGS_((Tcl_Interp *interp)); #endif /* TCL_TEST */ static void setargv _ANSI_ARGS_((int *argcPtr, char ***argvPtr)); +static BOOL __stdcall sigHandler (DWORD fdwCtrlType); +static Tcl_AsyncProc asyncExit; + +Tcl_AsyncHandler exitToken; +DWORD exitErrorCode; /* @@ -135,6 +140,12 @@ Tcl_AppInit(interp) return TCL_ERROR; } + /* + * Install a signal handler to the win32 console tclsh is running in. + */ + SetConsoleCtrlHandler(sigHandler, TRUE); + exitToken = Tcl_AsyncCreate(asyncExit, NULL); + #ifdef TCL_TEST if (Tcltest_Init(interp) == TCL_ERROR) { return TCL_ERROR; @@ -299,3 +310,70 @@ setargv(argcPtr, argvPtr) *argcPtr = argc; *argvPtr = argv; } + +/* + *---------------------------------------------------------------------- + * + * asyncExit -- + * + * The AsyncProc for the exitToken. + * + * Results: + * doesn't actually return. + * + * Side effects: + * tclsh cleanly exits. + * + *---------------------------------------------------------------------- + */ + +int +asyncExit (ClientData clientData, Tcl_Interp *interp, int code) +{ + Tcl_Exit((int)exitErrorCode); + + /* NOTREACHED */ + return code; +} + +/* + *---------------------------------------------------------------------- + * + * sigHandler -- + * + * Signal handler for the Win32 OS. Catches Ctrl+C, Ctrl+Break and + * other exits. This is needed so tclsh can do it's real clean-up + * and not an unclean crash terminate. + * + * Results: + * TRUE. + * + * Side effects: + * Effects the way the app exits from a signal. This is an + * operating system supplied thread and unsafe to call ANY + * Tcl commands except for Tcl_AsyncMark. + * + *---------------------------------------------------------------------- + */ + +BOOL __stdcall +sigHandler(DWORD fdwCtrlType) +{ + /* + * If Tcl is currently executing some bytecode or in the eventloop, + * this will cause Tcl to enter asyncExit at the next command + * boundry. + */ + exitErrorCode = fdwCtrlType; + Tcl_AsyncMark(exitToken); + + /* + * This will cause Tcl_Gets in Tcl_Main() to drop-out with an + * should it be blocked on input and our Tcl_AsyncMark didn't grab + * the attention of the interpreter. + */ + CloseHandle(GetStdHandle(STD_INPUT_HANDLE)); + + /* indicate to the OS not to call the default terminator */ + return TRUE; +} -- cgit v0.12