diff options
Diffstat (limited to 'win')
-rw-r--r-- | win/tclWin32Dll.c | 96 |
1 files changed, 90 insertions, 6 deletions
diff --git a/win/tclWin32Dll.c b/win/tclWin32Dll.c index c196705..8ffb697 100644 --- a/win/tclWin32Dll.c +++ b/win/tclWin32Dll.c @@ -10,11 +10,22 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclWin32Dll.c,v 1.48 2005/11/04 00:06:50 dkf Exp $ + * RCS: @(#) $Id: tclWin32Dll.c,v 1.49 2007/11/10 16:08:10 msofer Exp $ */ #include "tclWinInt.h" +#ifndef TCL_NO_STACK_CHECK +/* + * The following functions implement stack depth checking + */ +typedef struct ThreadSpecificData { + int *stackBound; /* The current stack boundary */ +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; +static int * CheckStackSpace(void) +#endif /* TCL_NO_STACK_CHECK */ + /* * The following data structures are used when loading the thunking library * for execing child processes under Win32s. @@ -511,16 +522,18 @@ TclWinNoBackslash( return path; } +#ifndef TCL_NO_STACK_CHECK /* *---------------------------------------------------------------------- * - * TclpCheckStackSpace -- + * CheckStackSpace -- * * Detect if we are about to blow the stack. Called before an evaluation * can happen when nesting depth is checked. * * Results: - * 1 if there is enough stack space to continue; 0 if not. + * A pointer to the deepest safe stack location that was determined, or + * NULL if we are about to blow the stack. * * Side effects: * None. @@ -528,8 +541,8 @@ TclWinNoBackslash( *---------------------------------------------------------------------- */ -int -TclpCheckStackSpace(void) +static int * +CheckStackSpace(void) { #ifdef HAVE_NO_SEH @@ -633,8 +646,79 @@ TclpCheckStackSpace(void) } __except (EXCEPTION_EXECUTE_HANDLER) {} #endif /* HAVE_NO_SEH */ - return retval; + if (retval) { + return (int *) ((char *)&retval - TCL_WIN_STACK_THRESHOLD); + } else { + return NULL; + } } +#endif + +/* + *---------------------------------------------------------------------- + * + * TclpGetStackParams -- + * + * Determine the stack params for the current thread: in which + * direction does the stack grow, and what is the stack lower (resp. + * upper) bound for safe invocation of a new command? This is used to + * cache the values needed for an efficient computation of + * TclpCheckStackSpace() when the interp is known. + * + * Results: + * Returns 1 if the stack grows down, in which case a stack lower bound + * is stored at stackBoundPtr. If the stack grows up, 0 is returned and + * an upper bound is stored at stackBoundPtr. If a bound cannot be + * determined NULL is stored at stackBoundPtr. + * + *---------------------------------------------------------------------- + */ + +#ifndef TCL_NO_STACK_CHECK +int +TclpGetCStackParams( + int ***stackBoundPtr) +{ + int localVar, *stackBound; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + /* Most variables are actually in a + * thread-specific data block to minimise the + * impact on the stack. */ + + if (!tsdPtr->stackBound || (&localVar < tsdPtr->stackBound)) { + /* + * First time through in this thread or apparent stack failure. If we + * didn't already blow up, we are within the safety area. Recheck with + * the OS to get a new estimate. + */ + + stackBound = CheckStackSpace(); + if (!stackBound) { + /* + * We are really blowing the stack! Do not update the estimate we + * already had, just return. + */ + + if (!tsdPtr->stackBound) { + /* + * ??? First time around: this thread was born with a stack + * smaller than TCL_WIN_STACK_THRESHOLD. What do we do now? + * Initialise to something that will always fail? Choose for + * instance 1K ints above the current depth. + */ + + tsdPtr->stackBound = (&localVar + 1024); + } + } else { + tsdPtr->stackBound = stackBound; + } + } + + *stackBoundPtr = &(tsdPtr->stackBound); + return 1; +} +#endif + /* *--------------------------------------------------------------------------- |