Attachment "unixStackCheck.v6.diff" to
ticket [746378ffff]
added by
dkf
2004-06-23 07:28:15.
? unixStackCheck.v5.diff
? unixStackCheck.v6.diff
? unixStackCheckV4.diff
? unix/autom4te.cache
? unix/dltest.marker
Index: ChangeLog
===================================================================
RCS file: /cvsroot/tcl/tcl/ChangeLog,v
retrieving revision 1.2099
diff -b -u -r1.2099 ChangeLog
--- ChangeLog 22 Jun 2004 22:08:36 -0000 1.2099
+++ ChangeLog 23 Jun 2004 00:19:32 -0000
@@ -1,3 +1,10 @@
+2004-06-23 Donal K. Fellows <[email protected]>
+
+ * unix/tclUnixInit.c (GetStackSize, TclpCheckStackSpace):
+ * unix/tclUnixThrd.c (TclpThreadGetStackSize): Added code to check
+ whether the C stack is about to be exceeded, from [Patch 746378]
+ by Joe Mistachkin but with substantial revisions.
+
2004-06-22 Kevin Kenny <[email protected]>
* generic/tclEvent.c (NewThreadProc): Fixed broken build on
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.166
diff -b -u -r1.166 tclInt.h
--- generic/tclInt.h 22 Jun 2004 13:08:59 -0000 1.166
+++ generic/tclInt.h 23 Jun 2004 00:19:34 -0000
@@ -1901,6 +1901,7 @@
EXTERN void TclpThreadDataKeySet _ANSI_ARGS_((
Tcl_ThreadDataKey *keyPtr, VOID *data));
EXTERN void TclpThreadExit _ANSI_ARGS_((int status));
+EXTERN int TclpThreadGetStackSize _ANSI_ARGS_((void));
EXTERN void TclRememberCondition _ANSI_ARGS_((Tcl_Condition *mutex));
EXTERN void TclRememberDataKey _ANSI_ARGS_((Tcl_ThreadDataKey *mutex));
EXTERN VOID TclRememberJoinableThread _ANSI_ARGS_((Tcl_ThreadId id));
Index: tests/stack.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/stack.test,v
retrieving revision 1.17
diff -b -u -r1.17 stack.test
--- tests/stack.test 22 Jun 2004 19:41:25 -0000 1.17
+++ tests/stack.test 23 Jun 2004 00:19:34 -0000
@@ -56,12 +56,10 @@
} {too many nested evaluations (infinite loop?)}
# Make sure that there is enough stack to run regexp even if we're
-# close to the recursion limit. [Bug 947070]
-
-test stack-3.1 {enough room for regexp near recursion limit} \
- -constraints { win } \
- -setup {
- set ::limit [interp recursionlimit {} 10000]
+# close to the recursion limit. [Bug 947070] [Patch 746378]
+test stack-3.1 {enough room for regexp near recursion limit} -setup {
+ set limit [interp recursionlimit {} 10000]
+ set depth 0
proc a { max } {
if { [info level] < $max } {
set ::depth [info level]
@@ -70,16 +68,14 @@
regexp {^ ?} x
}
}
- } -body {
- set ::depth 0
+} -body {
catch { a 10001 }
set depth2 $depth
- catch { a $::depth }
- expr { $depth2 - $depth }
- } -cleanup {
- interp recursionlimit {} $::limit
+ list [a $depth] [expr { $depth2 - $depth }]
+} -cleanup {
+ interp recursionlimit {} $limit
rename a {}
- } -result {1}
+} -result {1 1}
# cleanup
::tcltest::cleanupTests
Index: unix/configure
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/configure,v
retrieving revision 1.113
diff -b -u -r1.113 configure
--- unix/configure 18 Jun 2004 15:29:23 -0000 1.113
+++ unix/configure 23 Jun 2004 00:19:34 -0000
@@ -3280,6 +3280,124 @@
fi
done
+
+
+for ac_func in pthread_attr_get_np pthread_getattr_np
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+ echo "$as_me:$LINENO: checking for pthread_getattr_np declaration" >&5
+echo $ECHO_N "checking for pthread_getattr_np declaration... $ECHO_C" >&6
+ if test "${tcl_cv_grep_pthread_getattr_np+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <pthread.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "pthread_getattr_np" >/dev/null 2>&1; then
+ tcl_cv_grep_pthread_getattr_np=present
+else
+ tcl_cv_grep_pthread_getattr_np=missing
+fi
+rm -f conftest*
+
+fi
+
+ echo "$as_me:$LINENO: result: $tcl_cv_grep_pthread_getattr_np" >&5
+echo "${ECHO_T}$tcl_cv_grep_pthread_getattr_np" >&6
+ if test $tcl_cv_grep_pthread_getattr_np = missing ; then
+ cat >>confdefs.h <<\_ACEOF
+#define GETATTRNP_NOT_DECLARED 1
+_ACEOF
+
+ fi
LIBS=$ac_saved_libs
for ac_func in readdir_r
Index: unix/tcl.m4
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tcl.m4,v
retrieving revision 1.116
diff -b -u -r1.116 tcl.m4
--- unix/tcl.m4 18 Jun 2004 15:29:23 -0000 1.116
+++ unix/tcl.m4 23 Jun 2004 00:19:34 -0000
@@ -469,6 +469,16 @@
ac_saved_libs=$LIBS
LIBS="$LIBS $THREADS_LIBS"
AC_CHECK_FUNCS(pthread_attr_setstacksize)
+ AC_CHECK_FUNCS(pthread_attr_get_np pthread_getattr_np)
+ AC_MSG_CHECKING([for pthread_getattr_np declaration])
+ AC_CACHE_VAL(tcl_cv_grep_pthread_getattr_np,
+ AC_EGREP_HEADER(pthread_getattr_np, pthread.h,
+ tcl_cv_grep_pthread_getattr_np=present,
+ tcl_cv_grep_pthread_getattr_np=missing))
+ AC_MSG_RESULT($tcl_cv_grep_pthread_getattr_np)
+ if test $tcl_cv_grep_pthread_getattr_np = missing ; then
+ AC_DEFINE(GETATTRNP_NOT_DECLARED)
+ fi
LIBS=$ac_saved_libs
AC_CHECK_FUNCS(readdir_r)
else
Index: unix/tclUnixInit.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixInit.c,v
retrieving revision 1.45
diff -b -u -r1.45 tclUnixInit.c
--- unix/tclUnixInit.c 18 Jun 2004 15:26:00 -0000 1.45
+++ unix/tclUnixInit.c 23 Jun 2004 00:19:34 -0000
@@ -14,10 +14,12 @@
#include <CoreFoundation/CoreFoundation.h>
#endif
#include "tclInt.h"
+#include <stddef.h>
#include <locale.h>
#ifdef HAVE_LANGINFO
#include <langinfo.h>
#endif
+#include <sys/resource.h>
#if defined(__FreeBSD__)
# include <floatingpoint.h>
#endif
@@ -28,6 +30,69 @@
# endif
#endif
+/*
+ * Define this if you want to revert to the old behavior of
+ * never checking the stack.
+ */
+#undef TCL_NO_STACK_CHECK
+
+/*
+ * Define this if you want to see a lot of output regarding
+ * stack checking.
+ */
+#undef TCL_DEBUG_STACK_CHECK
+
+/*
+ * Values used to compute how much space is really available for Tcl's
+ * use for the stack.
+ *
+ * NOTE: Now I have some idea why the maximum stack size must be
+ * divided by 64 on FreeBSD with threads enabled to get a reasonably
+ * correct value.
+ *
+ * The getrlimit() function is documented to return the maximum stack
+ * size in bytes. However, with threads enabled, the pthread library
+ * does bad things to the stack size limits. First, the limits cannot
+ * be changed. Second, they appear to be reported incorrectly by a
+ * factor of about 64.
+ *
+ * The defines below may need to be adjusted if more platforms have
+ * this broken behavior with threads enabled.
+ */
+
+#if defined(__FreeBSD__)
+# define TCL_MAGIC_STACK_DIVISOR 64
+# define TCL_RESERVED_STACK_PAGES 3
+#endif
+
+#ifndef TCL_MAGIC_STACK_DIVISOR
+#define TCL_MAGIC_STACK_DIVISOR 1
+#endif
+#ifndef TCL_RESERVED_STACK_PAGES
+#define TCL_RESERVED_STACK_PAGES 8
+#endif
+
+/*
+ * Thread specific data for stack checking.
+ */
+
+#ifndef TCL_NO_STACK_CHECK
+typedef struct ThreadSpecificData {
+ int *outerVarPtr; /* The "outermost" stack frame pointer for
+ * this thread. */
+ int initialised; /* Have we found what the stack size was? */
+ int stackDetermineResult; /* What happened when we did that? */
+ size_t stackSize; /* The size of the current stack. */
+} ThreadSpecificData;
+static Tcl_ThreadDataKey dataKey;
+#endif /* TCL_NO_STACK_CHECK */
+
+#ifdef TCL_DEBUG_STACK_CHECK
+#define STACK_DEBUG(args) printf args
+#else
+#define STACK_DEBUG(args) (void)0
+#endif /* TCL_DEBUG_STACK_CHECK */
+
/* Used to store the encoding used for binary files */
static Tcl_Encoding binaryEncoding = NULL;
/* Has the basic library path encoding issue been fixed */
@@ -138,8 +203,13 @@
{NULL, NULL}
};
+#ifndef TCL_NO_STACK_CHECK
+static int GetStackSize _ANSI_ARGS_((size_t *stackSizePtr));
+#endif /* TCL_NO_STACK_CHECK */
#ifdef HAVE_CFBUNDLE
-static int Tcl_MacOSXGetLibraryPath(Tcl_Interp *interp, int maxPathLen, char *tclLibPath);
+static int MacOSXGetLibraryPath _ANSI_ARGS((
+ Tcl_Interp *interp, int maxPathLen,
+ char *tclLibPath));
#endif /* HAVE_CFBUNDLE */
@@ -201,7 +271,7 @@
#ifdef __FreeBSD__
fpsetround(FP_RN);
- fpsetmask(0L);
+ (void) fpsetmask(0L);
#endif
#if defined(__bsdi__) && (_BSDI_VERSION > 199501)
@@ -348,7 +418,6 @@
* (e.g. /usr/src/tcl8.4.0/unix/solaris-sparc/../../../tcl8.4.0/library)
*/
-
/*
* The variable path holds an absolute path. Take care not to
* overwrite pathv[0] since that might produce a relative path.
@@ -442,7 +511,7 @@
#ifdef HAVE_CFBUNDLE
char tclLibPath[MAXPATHLEN + 1];
- if (Tcl_MacOSXGetLibraryPath(NULL, MAXPATHLEN, tclLibPath) == TCL_OK) {
+ if (MacOSXGetLibraryPath(NULL, MAXPATHLEN, tclLibPath) == TCL_OK) {
str = tclLibPath;
} else
#endif /* HAVE_CFBUNDLE */
@@ -740,7 +809,7 @@
#ifdef HAVE_CFBUNDLE
char tclLibPath[MAXPATHLEN + 1];
- if (Tcl_MacOSXGetLibraryPath(interp, MAXPATHLEN, tclLibPath) == TCL_OK) {
+ if (MacOSXGetLibraryPath(interp, MAXPATHLEN, tclLibPath) == TCL_OK) {
CONST char *str;
Tcl_DString ds;
CFBundleRef bundleRef;
@@ -954,18 +1023,182 @@
int
TclpCheckStackSpace()
{
+#ifdef TCL_NO_STACK_CHECK
+
/*
- * This function is unimplemented on Unix platforms.
+ * This function was normally unimplemented on Unix platforms and
+ * this implements old behavior, i.e. no stack checking performed.
*/
return 1;
+
+#else
+
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ /* Most variables are actually in a
+ * thread-specific data block to minimise the
+ * impact on the stack. */
+ register ptrdiff_t stackUsed;
+ int localVar; /* Reference to somewhere on the local stack.
+ * This is declared last so it's as "deep" as
+ * possible. */
+
+ if (tsdPtr == NULL) {
+ /* this should probably be a panic(). */
+ Tcl_Panic("failed to get thread specific stack check data");
+ }
+
+ /*
+ * The first time through, we record the "outermost" stack frame.
+ */
+
+ if (tsdPtr->outerVarPtr == NULL) {
+ tsdPtr->outerVarPtr = &localVar;
+ }
+
+ if (tsdPtr->initialised == 0) {
+ /*
+ * We appear to have not computed the stack size before.
+ * Attempt to retrieve it from either the current thread or,
+ * failing that, the process accounting limit. Note that we
+ * assume that stack sizes do not change throughout the
+ * lifespan of the thread/process; this is almost always true.
+ */
+
+ tsdPtr->stackDetermineResult = GetStackSize(&tsdPtr->stackSize);
+ tsdPtr->initialised = 1;
+ }
+
+ switch (tsdPtr->stackDetermineResult) {
+ case TCL_BREAK:
+ STACK_DEBUG(("skipping stack check with failure\n"));
+ return 0;
+ case TCL_CONTINUE:
+ STACK_DEBUG(("skipping stack check with success\n"));
+ return 1;
+ }
+
+ /*
+ * Sanity check to see if somehow the stack started going the
+ * other way.
+ */
+
+ if (&localVar > tsdPtr->outerVarPtr) {
+ stackUsed = (char *)&localVar - (char *)tsdPtr->outerVarPtr;
+ } else {
+ stackUsed = (char *)tsdPtr->outerVarPtr - (char *)&localVar;
+ }
+
+ /*
+ * Now we perform the actual check. Are we about to blow
+ * our stack frame?
+ */
+
+ if (stackUsed < (ptrdiff_t) tsdPtr->stackSize) {
+ STACK_DEBUG(("stack OK\tin:%p\tout:%p\tuse:%04X\tmax:%04X\n",
+ &localVar, tsdPtr->outerVarPtr, stackUsed, tsdPtr->stackSize));
+ return 1;
+ } else {
+ STACK_DEBUG(("stack OVERFLOW\tin:%p\tout:%p\tuse:%04X\tmax:%04X\n",
+ &localVar, tsdPtr->outerVarPtr, stackUsed, tsdPtr->stackSize));
+ return 0;
+ }
+#endif /* TCL_NO_STACK_CHECK */
}
-#ifdef HAVE_CFBUNDLE
/*
*----------------------------------------------------------------------
*
- * Tcl_MacOSXGetLibraryPath --
+ * GetStackSize --
+ *
+ * Discover what the stack size for the current thread/process
+ * actually is. Expects to only ever be called once per thread
+ * and then only at a point when there is a reasonable amount of
+ * space left on the current stack; TclpCheckStackSpace is called
+ * sufficiently frequently that that is true.
+ *
+ * Results:
+ * TCL_OK if the stack space was discovered, TCL_BREAK if the
+ * stack space was undiscoverable in a way that stack checks
+ * should fail, and TCL_CONTINUE if the stack space was
+ * undiscoverable in a way that stack checks should succeed.
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+#ifndef TCL_NO_STACK_CHECK
+static int
+GetStackSize(stackSizePtr)
+ size_t *stackSizePtr;
+{
+ size_t rawStackSize;
+ struct rlimit rLimit; /* The result from getrlimit(). */
+
+#ifdef TCL_THREADS
+ rawStackSize = (size_t) TclpThreadGetStackSize();
+ if (rawStackSize == (size_t) -1) {
+ /*
+ * Some kind of confirmed error?!
+ */
+ return TCL_BREAK;
+ }
+ if (rawStackSize > 0) {
+ goto finalSanityCheck;
+ }
+
+ /*
+ * If we have zero or an error, try the system limits
+ * instead. After all, the pthread documentation states that
+ * threads should always be bound by the system stack size limit
+ * in any case.
+ */
+#endif /* TCL_THREADS */
+
+ if (getrlimit(RLIMIT_STACK, &rLimit) != 0) {
+ /*
+ * getrlimit() failed, just fail the whole thing.
+ */
+ return TCL_BREAK;
+ }
+ if (rLimit.rlim_cur == RLIM_INFINITY) {
+ /*
+ * Limit is "infinite"; there is no stack limit.
+ */
+ return TCL_CONTINUE;
+ }
+ rawStackSize = rLimit.rlim_cur;
+
+ /*
+ * Final sanity check on the determined stack size. If we fail
+ * this, assume there are bogus values about and that we can't
+ * actually figure out what the stack size really is.
+ */
+
+#ifdef TCL_THREADS /* Stop warning... */
+ finalSanityCheck:
+#endif
+ if (rawStackSize <= 0) {
+ return TCL_CONTINUE;
+ }
+
+ /*
+ * Calculate a stack size with a safety margin.
+ */
+
+ *stackSizePtr = (rawStackSize / TCL_MAGIC_STACK_DIVISOR)
+ - (getpagesize() * TCL_RESERVED_STACK_PAGES);
+
+ return TCL_OK;
+}
+#endif /* TCL_NO_STACK_CHECK */
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * MacOSXGetLibraryPath --
*
* If we have a bundle structure for the Tcl installation,
* then check there first to see if we can find the libraries
@@ -979,7 +1212,10 @@
*
*----------------------------------------------------------------------
*/
-static int Tcl_MacOSXGetLibraryPath(Tcl_Interp *interp, int maxPathLen, char *tclLibPath)
+
+#ifdef HAVE_CFBUNDLE
+static int
+MacOSXGetLibraryPath(Tcl_Interp *interp, int maxPathLen, char *tclLibPath)
{
int foundInFramework = TCL_ERROR;
if (strcmp(defaultLibraryDir, "@TCL_IN_FRAMEWORK@") == 0) {
@@ -989,4 +1225,3 @@
return foundInFramework;
}
#endif /* HAVE_CFBUNDLE */
-
Index: unix/tclUnixPort.h
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixPort.h,v
retrieving revision 1.37
diff -b -u -r1.37 tclUnixPort.h
--- unix/tclUnixPort.h 27 May 2004 13:18:55 -0000 1.37
+++ unix/tclUnixPort.h 23 Jun 2004 00:19:34 -0000
@@ -553,7 +553,7 @@
*/
#ifdef TCL_THREADS
-#include <pthread.h>
+# include <pthread.h>
typedef pthread_mutex_t TclpMutex;
EXTERN void TclpMutexInit _ANSI_ARGS_((TclpMutex *mPtr));
EXTERN void TclpMutexLock _ANSI_ARGS_((TclpMutex *mPtr));
@@ -562,25 +562,36 @@
EXTERN struct tm * TclpLocaltime(CONST time_t *);
EXTERN struct tm * TclpGmtime(CONST time_t *);
EXTERN char * TclpInetNtoa(struct in_addr);
-#define readdir(x) TclpReaddir(x)
+# define readdir(x) TclpReaddir(x)
/* #define localtime(x) TclpLocaltime(x)
* #define gmtime(x) TclpGmtime(x) */
-#undef inet_ntoa
-#define inet_ntoa(x) TclpInetNtoa(x)
-#undef TclOSreaddir
-#define TclOSreaddir(x) TclpReaddir(x)
-#ifdef MAC_OSX_TCL
+# undef inet_ntoa
+# define inet_ntoa(x) TclpInetNtoa(x)
+# undef TclOSreaddir
+# define TclOSreaddir(x) TclpReaddir(x)
+# ifdef MAC_OSX_TCL
/*
* On Mac OS X, realpath is currently not
* thread safe, c.f. SF bug # 711232.
*/
-#define NO_REALPATH
-#endif
+# define NO_REALPATH
+# endif
+# ifdef HAVE_PTHREAD_ATTR_GET_NP
+# include <pthread_np.h>
+# define TclpPthreadGetAttrs pthread_attr_get_np
+# else
+# ifdef HAVE_PTHREAD_GETATTR_NP
+# define TclpPthreadGetAttrs pthread_getattr_np
+# ifdef GETATTRNP_NOT_DECLARED
+EXTERN int pthread_getattr_np _ANSI_ARGS_((pthread_t, pthread_attr_t *));
+# endif
+# endif /* HAVE_PTHREAD_GETATTR_NP */
+# endif /* HAVE_PTHREAD_ATTR_GET_NP */
#else
typedef int TclpMutex;
-#define TclpMutexInit(a)
-#define TclpMutexLock(a)
-#define TclpMutexUnlock(a)
+# define TclpMutexInit(a)
+# define TclpMutexLock(a)
+# define TclpMutexUnlock(a)
#endif /* TCL_THREADS */
#endif /* _TCLUNIXPORT */
Index: unix/tclUnixThrd.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixThrd.c,v
retrieving revision 1.31
diff -b -u -r1.31 tclUnixThrd.c
--- unix/tclUnixThrd.c 22 Jun 2004 13:09:01 -0000 1.31
+++ unix/tclUnixThrd.c 23 Jun 2004 00:19:34 -0000
@@ -199,6 +199,55 @@
}
#endif /* TCL_THREADS */
+#ifdef TCL_THREADS
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclpThreadGetStackSize --
+ *
+ * This procedure returns the size of the current thread's stack.
+ *
+ * Results:
+ * Stack size (in bytes?) or -1 for error or 0 for undeterminable.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclpThreadGetStackSize()
+{
+#if defined(HAVE_PTHREAD_SETSTACKSIZE) && defined(TclpPthreadGetAttrs)
+ pthread_attr_t threadAttr; /* This will hold the thread attributes for
+ * the current thread. */
+ size_t stackSize;
+
+ if (pthread_attr_init(&threadAttr) != 0) {
+ return -1;
+ }
+ if (TclpPthreadGetAttrs(pthread_self(), &threadAttr) != 0) {
+ pthread_attr_destroy(&threadAttr);
+ return -1;
+ }
+ if (pthread_attr_getstacksize(&threadAttr, &stackSize) != 0) {
+ pthread_attr_destroy(&threadAttr);
+ return -1;
+ }
+ pthread_attr_destroy(&threadAttr);
+ return (int) stackSize;
+#else
+ /*
+ * Cannot determine the real stack size of this thread. The
+ * caller might want to try looking at the process accounting
+ * limits instead.
+ */
+ return 0;
+#endif
+}
+#endif /* TCL_THREADS */
+
/*
*----------------------------------------------------------------------
*