From 5b704020810cc6cd47e7e04537036e7e2c3fdf37 Mon Sep 17 00:00:00 2001 From: Miguel Sofer Date: Mon, 26 Nov 2007 19:11:10 +0000 Subject: * generic/tclBasic.c: * generic/tclInt.h: * unix/tclUnixInit.c: * unix/tclUnixThrd.c: Fix stack checking via workaround for bug in glibc's pthread_attr_get_np, patch from [Bug 1815573]. Many thanks to Sergei Golovan (aka Teo) for detecting the bug and helping diagnose and develop the fix. --- ChangeLog | 10 ++++++++++ generic/tclBasic.c | 9 ++++++++- generic/tclInt.h | 4 ++-- unix/tclUnixInit.c | 10 +++++----- unix/tclUnixThrd.c | 57 ++++++++++++++++++++++++++++++++++++++++++++---------- 5 files changed, 72 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index bc14de6..5f1a1b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2007-11-26 Miguel Sofer + + * generic/tclBasic.c: + * generic/tclInt.h: + * unix/tclUnixInit.c: + * unix/tclUnixThrd.c: Fix stack checking via workaround for bug in + glibc's pthread_attr_get_np, patch from [Bug 1815573]. Many thanks + to Sergei Golovan (aka Teo) for detecting the bug and helping + diagnose and develop the fix. + 2007-11-24 Donal K. Fellows * generic/tclCompCmds.c (TclCompileDictAppendCmd): Fix bug in [dict diff --git a/generic/tclBasic.c b/generic/tclBasic.c index bf8d8dc..0741813 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -14,7 +14,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclBasic.c,v 1.284 2007/11/23 22:11:31 dkf Exp $ + * RCS: @(#) $Id: tclBasic.c,v 1.285 2007/11/26 19:11:11 msofer Exp $ */ #include "tclInt.h" @@ -831,6 +831,13 @@ Tcl_CreateInterp(void) Tcl_Panic(Tcl_GetString(Tcl_GetObjResult(interp))); } + /* + * Insure that the stack checking mechanism for this interp is + * initialized. + */ + + TclInterpReady(interp); + return interp; } diff --git a/generic/tclInt.h b/generic/tclInt.h index 260b36a..48e4eac 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -13,7 +13,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclInt.h,v 1.352 2007/11/23 15:00:24 dkf Exp $ + * RCS: @(#) $Id: tclInt.h,v 1.353 2007/11/26 19:11:12 msofer Exp $ */ #ifndef _TCLINT @@ -2621,7 +2621,7 @@ MODULE_SCOPE void * TclpThreadDataKeyGet(Tcl_ThreadDataKey *keyPtr); 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); diff --git a/unix/tclUnixInit.c b/unix/tclUnixInit.c index 7f725cb..3d8ac40 100644 --- a/unix/tclUnixInit.c +++ b/unix/tclUnixInit.c @@ -7,7 +7,7 @@ * Copyright (c) 1999 by Scriptics Corporation. * All rights reserved. * - * RCS: @(#) $Id: tclUnixInit.c,v 1.80 2007/11/13 17:13:07 msofer Exp $ + * RCS: @(#) $Id: tclUnixInit.c,v 1.81 2007/11/26 19:11:13 msofer Exp $ */ #include "tclInt.h" @@ -1145,13 +1145,13 @@ GetStackSize( 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; diff --git a/unix/tclUnixThrd.c b/unix/tclUnixThrd.c index cb206f9..491613a 100644 --- a/unix/tclUnixThrd.c +++ b/unix/tclUnixThrd.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclUnixThrd.c,v 1.53 2007/11/16 11:17:28 dkf Exp $ + * RCS: @(#) $Id: tclUnixThrd.c,v 1.54 2007/11/26 19:11:13 msofer Exp $ */ #include "tclInt.h" @@ -216,24 +216,61 @@ TclpThreadExit( *---------------------------------------------------------------------- */ -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 @@ TclpThreadGetStackSize(void) * want to try looking at the process accounting limits instead. */ #endif - return (int) stackSize; + return stackSize; } #endif /* TCL_THREADS */ -- cgit v0.12