Intro
Some scripts in test suite for module
HTTP::WebTest which I maintain
use
fork for creation of child proccess - test HTTP servers. I'm
used to debug problems in my code with
perl debugger so I was
interested how can I use it with scripts which use
fork. I found
that perl debugger does provides support for such scripts but this
feature is completely undocumented.
Note that techniques described in this article probably work only on
UNIX and UNIX-like systems. This article is probably is not very easy
reading because its topic is quite complex itself.
Debugging Several Proccesses at Same Time
I need TTY
After
fork there are more than one process and more than one instance
of perl debugger. The problem is that each instance of perl debugger
requires its own TTY. Right after
fork instance of perl debugger which
runs in child process tries to switch TTY. If it can't do that it
tries to use same TTY as perl debugger which runs in parent
process. This can result sometimes with either screwed TTY or
runaway child process which takes 100% of CPU.
How can debugger in child process find free TTY? Perl debugger can use
undocumented variables $DB::fork_TTY or undocumented subroutine
$DB::get_fork_TTY to find avialable TTY or it can try to start xterm process and use xterm's
TTY.
How it works?
- First of all if there exists subroutine $DB::get_fork_TTY debugger
calls it. Debugger ignores value returned by this subroutine but this
subroutine can set value of variable $DB::fork_TTY.
- Second of all if defined variable $DB::fork_TTY debugger will
treat it's value as name of TTY device and will try to use this
device. Note that debugger doesn't check if it is really TTY
device. If it doesn't then child process gets into infinite loop
taking 100% of CPU.
- If $DB::fork_TTY is not defined but debugger detects that it runs
inside xterm it tries to launch another xterm and it tries to use new
xterm's TTY.
Easiest option is run your script with debugger in xterm. On fork
debugger will create additional xterm window.
Another option - define subroutine $DB::get_fork_TTY. It should
somehow find new TTYs and set $DB::fork_TTY value
accordantly. Example:
sub DB::get_fork_TTY {
open XT, q[3>&1 xterm -title 'Forked Perl debugger' -e sh -c 'tty
+1>&3;\ sleep 10000000' |];
$DB::fork_TTY = <XT>;
chomp $DB::fork_TTY;
}
And the last option - just set manually $DB::fork_TTY.
Some Useful Tricks (Kinda Q&A)
- How can be created additional free TTY? Start terminal emulator
like xterm, type 'tty' to get TTY device name and 'sleep 10000000'.
- How can debugger related code (like definition of DB::get_fork_TTY
or $DB::fork_TTY) be put outside scripts? Create file MyDebug.pm and
put it where. When you are using perl debugger use
perl -MMyDebug -d script.pl
instead of just
perl -d script.pl
or even better just set environment variable PERL5OPT to '-MMyDebug'.
- Is where any way to ignore a child process (that is don't give it
it's own TTY) if there is no need to debug the child process? It is
possible. Actually every process running with the debugger requires it's
own TTY only when it breaks into the debugger. If you don't have any break
points in the child process it will break into the debugger only on an exit. Since
the debugger in the child process doesn't have it's own TTY it should not be
allowed to break on the exit of the child process. There is exist a variable
$DB::inhibit_exit which forbids the debugger to break on the process
exit if it is set to false.
You can add
$DB::inhibit_exit = 0;
in your script after fork so
the debugger in the child process will not try to break the child process
on its exit.
See Also
perldoc perldebug,
Using the Perl Debugger and sources of perl debugger (perl5db.pl).
P.S.
I'm gladly accepting correction for this article. Including corrections for my poor English.
Update: Thanks for correction cybear.