From: R. B. <ro...@pa...> - 2003-04-01 06:38:42
|
Chet Ramey writes: > The integration of your patches to the mainline bash code is complete. The > result passes all of the tests added to the bash suite, with a single > exception. The primary difference is: Many thanks for integrating the debugging support patches into the mainline bash code. I look forward to the day when the sourceforge copy can be removed! > The primary difference is: > > 1. The RETURN trap is executed whenever a script run with `.' or `source' > finishes, not just when it calls `return'. This is an improvement and an oversight or coding inexperience on my part. > > (This mirrors the behavior of shell functions.) Great! > > I have a couple of questions for discussion: > > 1. Why do scripts executed with `.' or `source' inherit the RETURN trap? > Shell functions don't. > > 2. Why do command substitutions inherit the RETURN trap? > The code that implements this policy, I think, is this code in execute_cmd.c: /* Reset debug, error and return trap handlers. Set up to restore them on return. .... return_trap = TRAP_STRING(RETURN_TRAP); if (return_trap) ... versus this code in trap.c: /* Command substitution and other child processes don't inherit the debug or error traps. */ if (!function_trace_mode) sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED; I envisioned the RETURN trap for two purposes. The first was to be able to implement a gdb "finish" command. (Since gdb's "return" command means something else, the name RETURN might be confusing here. I really don't know). Here, the RETURN trap I think should mimic behavior of "set -o fntrace" (or variable function_trace_mode). That is, when one requests the facility to debug into a function, with that should also get the ability to catch an an exit out of that function. Assuming that philosophy, the code cited above for execute_cmd.c is flawed and should be: if (!function_trace_mode && return_trap) The second intended use for the RETURN trap was precisely to catch a subshell exit. Some background. A debugger such as this one lives inside the environment of the debugged program. But one would like to think of the global debugger state (such as breakpoints and debugger settings) as being outside and independent of the debugged program. There is a problem in passing state or part of the environment from a nested bash session (SHLVL) or a subshell out to the parent environment. In a sense I think of this as a general POSIX shell problem. There's an "export" command to the child but no "export" to parent. In order to simulate "export to parent", currently the bash debugger has to do this in a very inefficient way. Any variable that is to be exported to the parent is written to a journal file. The file may contain the entire history of the changes of that variable. For example x=1; ... x=2; ... unset x; ... x=3. In fact, the only relevant value is the last one set/unset. Every time DEBUG trap is called, we have to source in that journal (if it exists); the only time it can be removed and can stop recording changes to the journal is when we get back to the initial SHLVL and there are no subshells. Okay. Sorry for the long-winded background. We finally get to that second use and what a trap RETURN routine could do to help the export-to-parent problem. It would be best to have two trap calls. Just before the exit, variables marked "export" would be saved. And just after the exit, the parent would read in those saved values. Even if you have only one call it'd still save a bit of the unnecessary work. If I had a return in the child, rather than saving the entire history of value changes, I might be able to just save the last value of the marked variables. (I'd still have to have a list of marked variables). If I had a RETURN trap call in the parent, I would only have to read in this journal file once, even though the file might contain overwritten variable assignments. > Thanks for all your hard work. My pleasure and even more thanks thanks for all of *your* hard work! |