summaryrefslogtreecommitdiffstats
path: root/win/tclWin32Dll.c
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2007-11-12 19:18:11 (GMT)
committerdgp <dgp@users.sourceforge.net>2007-11-12 19:18:11 (GMT)
commit19ff89ec05fbfdb2e383a89c9f522e5474f484fd (patch)
tree7795d4849bbe3267bf65b73119c570602cce9a73 /win/tclWin32Dll.c
parent0a7049c4674056ec95788074fd9275355f9e1b7f (diff)
downloadtcl-19ff89ec05fbfdb2e383a89c9f522e5474f484fd.zip
tcl-19ff89ec05fbfdb2e383a89c9f522e5474f484fd.tar.gz
tcl-19ff89ec05fbfdb2e383a89c9f522e5474f484fd.tar.bz2
merge updates from HEAD
Diffstat (limited to 'win/tclWin32Dll.c')
-rw-r--r--win/tclWin32Dll.c172
1 files changed, 67 insertions, 105 deletions
diff --git a/win/tclWin32Dll.c b/win/tclWin32Dll.c
index c196705..76aab7c 100644
--- a/win/tclWin32Dll.c
+++ b/win/tclWin32Dll.c
@@ -10,11 +10,21 @@
* 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.48.8.1 2007/11/12 19:18:24 dgp 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;
+#endif /* TCL_NO_STACK_CHECK */
+
/*
* The following data structures are used when loading the thunking library
* for execing child processes under Win32s.
@@ -514,127 +524,79 @@ TclWinNoBackslash(
/*
*----------------------------------------------------------------------
*
- * TclpCheckStackSpace --
+ * TclpGetStackParams --
*
- * Detect if we are about to blow the stack. Called before an evaluation
- * can happen when nesting depth is checked.
+ * 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:
- * 1 if there is enough stack space to continue; 0 if not.
- *
- * Side effects:
- * None.
+ * 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
-TclpCheckStackSpace(void)
+TclpGetCStackParams(
+ int **stackBoundPtr)
{
-
-#ifdef HAVE_NO_SEH
- EXCEPTION_REGISTRATION registration;
-#endif
- int retval = 0;
-
- /*
- * We can recurse only if there is at least TCL_WIN_STACK_THRESHOLD bytes
- * of stack space left. alloca() is cheap on windows; basically it just
- * subtracts from the stack pointer causing the OS to throw an exception
- * if the stack pointer is set below the bottom of the stack.
- */
-
-#ifdef HAVE_NO_SEH
- __asm__ __volatile__ (
-
- /*
- * Construct an EXCEPTION_REGISTRATION to protect the call to __alloca
- */
-
- "leal %[registration], %%edx" "\n\t"
- "movl %%fs:0, %%eax" "\n\t"
- "movl %%eax, 0x0(%%edx)" "\n\t" /* link */
- "leal 1f, %%eax" "\n\t"
- "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */
- "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */
- "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */
- "movl %[error], 0x10(%%edx)" "\n\t" /* status */
-
- /*
- * Link the EXCEPTION_REGISTRATION on the chain
- */
-
- "movl %%edx, %%fs:0" "\n\t"
-
- /*
- * Attempt a call to __alloca, to determine whether there's sufficient
- * memory to be had.
- */
-
- "movl %[size], %%eax" "\n\t"
- "pushl %%eax" "\n\t"
- "call __alloca" "\n\t"
-
- /*
- * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION and
- * store a TCL_OK status
- */
-
- "movl %%fs:0, %%edx" "\n\t"
- "movl %[ok], %%eax" "\n\t"
- "movl %%eax, 0x10(%%edx)" "\n\t"
- "jmp 2f" "\n"
-
- /*
- * Come here on an exception. Get the EXCEPTION_REGISTRATION that we
- * previously put on the chain.
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ SYSTEM_INFO si; /* The system information, used to
+ * determine the page size */
+ MEMORY_BASIC_INFORMATION mbi;
+ /* The information about the memory
+ * area in which the stack resides */
+
+ if (!tsdPtr->stackBound
+ || ((DWORD_PTR)&tsdPtr < (DWORD_PTR)tsdPtr->stackBound)) {
+
+ /*
+ * Either we haven't determined the stack bound in this thread,
+ * or else we've overflowed the bound that we previously
+ * determined. We need to find a new stack bound from
+ * Windows.
*/
- "1:" "\t"
- "movl %%fs:0, %%edx" "\n\t"
- "movl 0x8(%%edx), %%edx" "\n\t"
+ GetSystemInfo(&si);
+ if (VirtualQuery((LPCVOID) &tsdPtr, &mbi, sizeof(mbi)) == 0) {
- /*
- * Come here however we exited. Restore context from the
- * EXCEPTION_REGISTRATION in case the stack is unbalanced.
- */
+ /* For some reason, the system didn't let us query the
+ * stack size. Nevertheless, we got here and haven't
+ * blown up yet. Don't update the calculated stack bound.
+ * If there is no calculated stack bound yet, set it to
+ * the base of the current page of stack. */
- "2:" "\t"
- "movl 0xc(%%edx), %%esp" "\n\t"
- "movl 0x8(%%edx), %%ebp" "\n\t"
- "movl 0x0(%%edx), %%eax" "\n\t"
- "movl %%eax, %%fs:0" "\n\t"
+ if (!tsdPtr->stackBound) {
+ tsdPtr->stackBound =
+ (int*) ((DWORD_PTR)(&tsdPtr)
+ & ~ (DWORD_PTR)(si.dwPageSize - 1));
+ }
- :
- /* No outputs */
- :
- [registration] "m" (registration),
- [ok] "i" (TCL_OK),
- [error] "i" (TCL_ERROR),
- [size] "i" (TCL_WIN_STACK_THRESHOLD)
- :
- "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"
- );
- retval = (registration.status == TCL_OK);
+ } else {
-#else /* !HAVE_NO_SEH */
- __try {
-#ifdef HAVE_ALLOCA_GCC_INLINE
- __asm__ __volatile__ (
- "movl %0, %%eax" "\n\t"
- "call __alloca" "\n\t"
- :
- : "i"(TCL_WIN_STACK_THRESHOLD)
- : "%eax");
-#else
- alloca(TCL_WIN_STACK_THRESHOLD);
-#endif /* HAVE_ALLOCA_GCC_INLINE */
- retval = 1;
- } __except (EXCEPTION_EXECUTE_HANDLER) {}
-#endif /* HAVE_NO_SEH */
+ /* The allocation base of the stack segment has to be advanced
+ * by one page (to allow for the guard page maintained in the
+ * C runtime) and then by TCL_WIN_STACK_THRESHOLD (to allow
+ * for the amount of stack that Tcl needs).
+ */
- return retval;
+ tsdPtr->stackBound =
+ (int*) ((DWORD_PTR)(mbi.AllocationBase)
+ + (DWORD_PTR)(si.dwPageSize)
+ + TCL_WIN_STACK_THRESHOLD);
+ }
+ }
+ *stackBoundPtr = tsdPtr->stackBound;
+ return 1;
}
+#endif
+
/*
*---------------------------------------------------------------------------