Index: TODO =================================================================== diff -u -rad24a87ea5581cd818fd8cc5f17668d1a63db97d -r8c8969ab850d118f76305689bd95e980b8f4543f --- TODO (.../TODO) (revision ad24a87ea5581cd818fd8cc5f17668d1a63db97d) +++ TODO (.../TODO) (revision 8c8969ab850d118f76305689bd95e980b8f4543f) @@ -3952,6 +3952,13 @@ r.zaumseil for noting this). - protect serial generation for parameters via mutex +- added compile macro NSF_STACKCHECK to provide stack monitoring/debugging + (especially useful for multi threaded programs, where stack + is more limited) +- make ::nsf::log more robust for aolserver/naviserver, since ::ns_log is + not always around when an output is needed + + ======================================================================== TODO: Index: generic/nsf.c =================================================================== diff -u -rad24a87ea5581cd818fd8cc5f17668d1a63db97d -r8c8969ab850d118f76305689bd95e980b8f4543f --- generic/nsf.c (.../nsf.c) (revision ad24a87ea5581cd818fd8cc5f17668d1a63db97d) +++ generic/nsf.c (.../nsf.c) (revision 8c8969ab850d118f76305689bd95e980b8f4543f) @@ -9943,6 +9943,24 @@ assert (object->teardown); assert (cmd); + +#if defined(NSF_STACKCHECK) + { int somevar; + NsfRuntimeState *rst = RUNTIME_STATE(interp); + + if (rst->exitHandlerDestroyRound == NSF_EXITHANDLER_OFF) { + if ((void *)&somevar > rst->bottomOfStack) { + NsfLog(interp, NSF_LOG_WARN, "Stack adjust bottom %ld", + rst->bottomOfStack - (void *)&somevar); + rst->bottomOfStack = (void *)&somevar; + } else if ((void *)&somevar < rst->maxStack) { + NsfLog(interp, NSF_LOG_WARN, "Stack adjust top %ld %s", + rst->bottomOfStack - (void *)&somevar, methodName); + rst->maxStack = (void *)&somevar; + } + } + } +#endif /*fprintf(stderr, "MethodDispatch method '%s.%s' objc %d flags %.6x\n", ObjectName(object), methodName, objc, flags); */ @@ -12404,6 +12422,9 @@ Tcl_Obj *CONST *objv = pcPtr->full_objv; int objc = pcPtr->objc+1; int result; + CONST char *fullMethodName = ObjStr(procNameObj); + Tcl_CallFrame *framePtr; + Proc *procPtr; #if defined(NSF_PROFILE) struct timeval trt; @@ -12414,14 +12435,30 @@ } #endif +#if defined(NSF_STACKCHECK) + { int somevar; + NsfRuntimeState *rst = RUNTIME_STATE(interp); + + if (rst->exitHandlerDestroyRound == NSF_EXITHANDLER_OFF) { + if ((void *)&somevar > rst->bottomOfStack) { + NsfLog(interp, NSF_LOG_WARN, "Stack adjust bottom %ld - nsfProc %s", + rst->bottomOfStack - (void *)&somevar, fullMethodName); + rst->bottomOfStack = (void *)&somevar; + } else if ((void *)&somevar < rst->maxStack) { + NsfLog(interp, NSF_LOG_WARN, "Stack adjust top %ld - nsfProc %s", + rst->bottomOfStack - (void *)&somevar, fullMethodName); + rst->maxStack = (void *)&somevar; + } + } + } +#endif + /* * The code below is derived from the scripted method dispatch and just * slightly adapted to remove object dependencies. */ - CONST char *fullMethodName = ObjStr(procNameObj); - Tcl_CallFrame *framePtr; - Proc *procPtr; + /*fprintf(stderr, "fullMethodName %s epoch %d\n", fullMethodName, Tcl_Command_cmdEpoch(cmd));*/ if (Tcl_Command_cmdEpoch(cmd)) { @@ -18755,6 +18792,14 @@ NsfFinalizeCmd(Tcl_Interp *interp, int withKeepvars) { int result; +#if defined(NSF_STACKCHECK) + {NsfRuntimeState *rst = RUNTIME_STATE(interp); + + NsfLog(interp, NSF_LOG_WARN, "Stack max usage %ld", + labs(rst->maxStack - rst->bottomOfStack)); + } +#endif + /*fprintf(stderr, "+++ call tcl-defined exit handler\n"); */ /* @@ -24379,7 +24424,6 @@ sizeof(Namespace), sizeof(Command), sizeof(Tcl_HashTable)); */ - #if defined(NSF_PROFILE) NsfProfileInit(interp); #endif @@ -24388,6 +24432,18 @@ rst->doCheckResults = 1; rst->doCheckArguments = 1; +#if defined(NSF_STACKCHECK) + { int someVar; + /* + * Note that Nsf_Init() is called typically via a package require, which + * is therefore not really the bottom of the stack, but just a first + * approximization. + */ + rst->bottomOfStack = &someVar; + rst->maxStack = rst->bottomOfStack; + } +#endif + /* * Check, if the namespace exists, otherwise create it. */ Index: generic/nsf.h =================================================================== diff -u -rce0137b1e49a9b27857eed54eea074427848d26d -r8c8969ab850d118f76305689bd95e980b8f4543f --- generic/nsf.h (.../nsf.h) (revision ce0137b1e49a9b27857eed54eea074427848d26d) +++ generic/nsf.h (.../nsf.h) (revision 8c8969ab850d118f76305689bd95e980b8f4543f) @@ -140,8 +140,10 @@ #define CMD_RESOLVER_TRACE 1 #define NRE_CALLBACK_TRACE 1 #define METHOD_OBJECT_TRACE 1 +#define NSF_STACKCHECK 1 */ + /* * Sanity checks and dependencies for optional compile flags */ Index: generic/nsfInt.h =================================================================== diff -u -r3e2056578f71e9fb14f5c1ee35a9d626747eb285 -r8c8969ab850d118f76305689bd95e980b8f4543f --- generic/nsfInt.h (.../nsfInt.h) (revision 3e2056578f71e9fb14f5c1ee35a9d626747eb285) +++ generic/nsfInt.h (.../nsfInt.h) (revision 8c8969ab850d118f76305689bd95e980b8f4543f) @@ -810,6 +810,10 @@ #if defined(NSF_PROFILE) NsfProfile profile; #endif +#if defined(NSF_STACKCHECK) + void *bottomOfStack; + void *maxStack; +#endif NsfStringIncrStruct iss; /* used for new to create new symbols */ short guardCount; /* keep track of guard invocations */ ClientData clientData; Index: generic/predefined.h =================================================================== diff -u -r7fc4e2328836d9695959eadb25dc5326dbcf8efb -r8c8969ab850d118f76305689bd95e980b8f4543f --- generic/predefined.h (.../predefined.h) (revision 7fc4e2328836d9695959eadb25dc5326dbcf8efb) +++ generic/predefined.h (.../predefined.h) (revision 8c8969ab850d118f76305689bd95e980b8f4543f) @@ -55,7 +55,9 @@ "::nsf::exithandler unset\n" "if {[info command ::ns_log] ne \"\"} {\n" "proc ::nsf::log {level msg} {\n" -"ns_log $level \"nsf: $msg\"}} else {\n" +"if {[info command ::ns_log] ne \"\"} {\n" +"::ns_log $level \"nsf: $msg\"} else {\n" +"puts stderr \"$level: $msg\"}}} else {\n" "proc ::nsf::log {level msg} {\n" "puts stderr \"$level: $msg\"}}\n" "proc ::nsf::deprecated {what oldCmd newCmd} {\n"