Tcl Source Code

Artifact [a1ccb7eb08]
Login

Artifact a1ccb7eb0833c0b7762a89d001258d9ea1d89771:

Attachment "stack.patch" to ticket [1815573fff] added by msofer 2007-11-26 20:49:03.
Index: generic/tclBasic.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclBasic.c,v
retrieving revision 1.284
diff -u -r1.284 tclBasic.c
--- generic/tclBasic.c	23 Nov 2007 22:11:31 -0000	1.284
+++ generic/tclBasic.c	26 Nov 2007 13:45:58 -0000
@@ -831,6 +831,13 @@
 	Tcl_Panic(Tcl_GetString(Tcl_GetObjResult(interp)));
     }
 
+    /*
+     * Insure that the stack checking mechanism for this interp is
+     * initialized. 
+     */
+    
+    TclInterpReady(interp);
+    
     return interp;
 }
 
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.352
diff -u -r1.352 tclInt.h
--- generic/tclInt.h	23 Nov 2007 15:00:24 -0000	1.352
+++ generic/tclInt.h	26 Nov 2007 13:45:58 -0000
@@ -2621,7 +2621,7 @@
 MODULE_SCOPE void	TclpThreadDataKeySet(Tcl_ThreadDataKey *keyPtr,
 			    void *data);
 MODULE_SCOPE void	TclpThreadExit(int status);
-MODULE_SCOPE int	TclpThreadGetStackSize(void);
+MODULE_SCOPE size_t	TclpThreadGetStackSize(void);
 MODULE_SCOPE void	TclRememberCondition(Tcl_Condition *mutex);
 MODULE_SCOPE void	TclRememberJoinableThread(Tcl_ThreadId id);
 MODULE_SCOPE void	TclRememberMutex(Tcl_Mutex *mutex);
Index: unix/tclUnixInit.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixInit.c,v
retrieving revision 1.80
diff -u -r1.80 tclUnixInit.c
--- unix/tclUnixInit.c	13 Nov 2007 17:13:07 -0000	1.80
+++ unix/tclUnixInit.c	26 Nov 2007 13:45:58 -0000
@@ -1145,13 +1145,13 @@
     struct rlimit rLimit;	/* The result from getrlimit(). */
 
 #ifdef TCL_THREADS
-    rawStackSize = (size_t) TclpThreadGetStackSize();
+    rawStackSize = TclpThreadGetStackSize();
     if (rawStackSize == (size_t) -1) {
 	/*
-	 * Some kind of confirmed error?!
+	 * Some kind of confirmed error in TclpThreadGetStackSize?! Fall back
+	 * to whatever getrlimit can determine.
 	 */
-	STACK_DEBUG(("skipping stack checks with failure\n"));
-	return TCL_BREAK;
+	STACK_DEBUG(("stack checks: TclpThreadGetStackSize failed in \n"));
     }
     if (rawStackSize > 0) {
 	goto finalSanityCheck;
Index: unix/tclUnixThrd.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixThrd.c,v
retrieving revision 1.53
diff -u -r1.53 tclUnixThrd.c
--- unix/tclUnixThrd.c	16 Nov 2007 11:17:28 -0000	1.53
+++ unix/tclUnixThrd.c	26 Nov 2007 13:45:58 -0000
@@ -216,24 +216,61 @@
  *----------------------------------------------------------------------
  */
 
-int
+size_t
 TclpThreadGetStackSize(void)
 {
     size_t stackSize = 0;
 #if defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) && defined(TclpPthreadGetAttrs)
     pthread_attr_t threadAttr;	/* This will hold the thread attributes for
 				 * the current thread. */
+    static int initialized = 0;
 
-    if (pthread_attr_init(&threadAttr) != 0) {
-	return -1;
-    }
-    if (TclpPthreadGetAttrs(pthread_self(), &threadAttr) != 0) {
-	pthread_attr_destroy(&threadAttr);
-	return -1;
+    /*
+     * Fix for [Bug 1815573]
+     *
+     * DESCRIPTION:
+     * On linux TclpPthreadGetAttrs (which is pthread_attr_get_np) may return
+     * bogus values on the initial thread. We have a choice: either use the
+     * default thread stack (first branch in the #if below), or return 0 and
+     * let getrlimit do its thing. 
+     *
+     * ASSUMPTIONS:
+     * There seems to be no api to determine if we are on the initial
+     * thread. The simple scheme implemented here assumes:
+     *   1. The first Tcl interp to be created lives in the initial thread. If
+     *      this assumption is not true, the fix is to call
+     *      TclpThreadGetStackSize from the initial thread previous to
+     *      creating any Tcl interpreter. In this case, especially if another
+     *      Tcl interpreter may be created in the initial thread, it might be
+     *      better to enable the second branch in the #if below
+     *   2. There will be no races in creating the first Tcl interp - ie, the
+     *      second Tcl interp will be created only after the first call to
+     *      Tcl_CreateInterp returns.
+     *
+     * These assumptions are satisfied by tclsh. Embedders may want to check
+     * their validity, and possibly adapt the code on failing to meet them.
+     */
+
+    if (!initialized) {
+	initialized = 1;
+#if 0
+	if (pthread_attr_init(&threadAttr) != 0) {
+	    return 0;
+	}
+#else
+	return 0;
+#endif
+    } else {
+	if (TclpPthreadGetAttrs(pthread_self(), &threadAttr) != 0) {
+	    pthread_attr_destroy(&threadAttr);
+	    return (size_t)-1;
+	}
     }
+
+    
     if (pthread_attr_getstacksize(&threadAttr, &stackSize) != 0) {
 	pthread_attr_destroy(&threadAttr);
-	return -1;
+	return (size_t)-1;
     }
     pthread_attr_destroy(&threadAttr);
 #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP)
@@ -251,7 +288,7 @@
      * want to try looking at the process accounting limits instead.
      */
 #endif
-    return (int) stackSize;
+    return stackSize;
 }
 #endif /* TCL_THREADS */