Process library and signals
Glynn Clements
glynn at gclements.plus.com
Tue Oct 26 18:38:14 EDT 2004
Having looked at the latest version of the Process library, it appears
that my earlier comments about signal handling may have been
misinterpreted.
First, my comments regarding the handling of SIGINT/SIGQUIT were
specific to system(). The C system() function ignores these signals in
the parent while the child is executing. However, this doesn't
necessarily apply to other functions; e.g. popen() doesn't ignore
these signals, and runProcess probably shouldn't either.
With system(), the parent blocks until the child is finished, so if
the user presses Ctrl-C to kill the "currently executing" process,
they probably want to kill the child. If the parent wants to die on
Ctrl-C, it can use WIFSIGNALED/WTERMSIG to determine that the child
was killed and terminate itself.
OTOH, with popen(), the parent continues to run alongside the child,
with the child behaving as a "slave", so the parent will normally want
to control the signal handling.
Ideally, system() equivalents (e.g. system, rawSystem) would ignore
the signals in the parent, popen() equivalents (e.g.
runInteractiveProcess) wouldn't, and lower-level functions (e.g.
runProcess) would give you a choice.
Unfortunately, there is an inherent conflict between portability and
generality, as the Unix and Windows interfaces are substantially
different. Unix has separate fork/exec primitives, with the option to
execute arbitrary code between the two, whilst Windows has a single
primitive with a fixed set of options.
Essentially, I'm not sure that a Windows-compatible runProcess would
be sufficiently general to accurately implement both system() and
popen() equivalents on Unix. Either system/rawSystem should be
implemented using lower-level functions (i.e. not runProcess) or
runProcess needs an additional option to control the handling of
signals in the child.
Also, my comment regarding the signals being "reset" in the child was
inaccurate. system() doesn't reset them in the sense of SIG_DFL. It
sets them to SIG_IGN before the fork(), recording their previous
handlers. After the fork, it resets them in the child to the values
they had upon entry to the system() function (i.e. to the values they
had before they were ignored). The effect is as if they had been set
to SIG_IGN in the parent after the fork(), but without the potential
race condition.
Thus, if they were originally ignored in the parent before system()
was entered, they will be ignored in the child. If they were at their
defaults (SIG_DFL) before system() was entered, they will be so in the
child. If they had been set to specific handlers, system() will
restore those handlers in the child, but then execve() will reset them
to SIG_DFL, as the handler functions won't exist after the execve().
--
Glynn Clements <glynn at gclements.plus.com>
More information about the Glasgow-haskell-users
mailing list