bug-gawk
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [bug-gawk] system() should return != 0 when the process is killed


From: Stephane Chazelas
Subject: Re: [bug-gawk] system() should return != 0 when the process is killed
Date: Sun, 6 Mar 2016 19:14:51 +0000
User-agent: Mutt/1.5.21 (2010-09-15)

2016-03-05 20:40:50 +0100, Isabella Parakiss:
[...]
> Also worth noting, gawk exits with 0 in this case:
> $ seq 3 | awk '{ print "<" $0 ">"; system("sleep 2") }'
> <1>
> ^C<2>
> ^C<3>
> ^C
[...]

Note that it's a different discussion. The initial report was
about the value returned by system() (which with gawk and
Solaris' /usr/xpg4/bin/awk is 0 when sleep is called by SIGINT),
the OP wasn't questioning the fact that awk wasn't killed upon
SIGINT.

POSIX, says the behaviour of awk's system() should be as if
system(3) was being used. And system(3) is meant to ignore
SIGINT in the parent.

Now, the rationale behind system(3) ignoring SIGINT/SIGQUIT is
that the application would then check the return status (the
number returned by SIGINT) and take appropriate action (like
kill itself with SIGINT if the exit status indicates a death by
SIGINT, if that's what they want to do (like in a
non-interactive application) or just report an error (think for
instance vi calling system() for its "!" ex command).

awk scripts however are generally non-interactive, most current
implementations don't let you know if the process died of a
SIGINT/SIGQUIT, and killing yourself with SIGINT is awkward
(system("kill -s INT \"$PPID\"") wouldn't work as the parent
ignores SIGINT if using system(3), so you'd need to use the
pipeline form).

So, it's not very clear what's the best thing to do here.

Note that it's a problem encountered by non-interactive shells
as well and addressed differently in different shells. Some
shells like bash and ksh93 implement the recommended behaviour
described at http://www.cons.org/cracauer/sigint.html:
the "wait and cooperative exit" (WCE) behaviour whereby the calling
application (the shell, or awk here) blocks SIGINT/SIGQUIT,
waits for the termination of the child process and if the
application ignored/handled the SIGINT, carry on as normal, but
if the child died of SIGINT, then exit by killing oneself with
SIGINT so as to report to the parent that you died of SIGINT.

ATM for system(), mawk implements "IUE" (for "immediate
unconditional exit") and gawk and traditional awk
implementations would be doing something like WNE (wait
and never exits). While for close() on a pipeline, all awk
implementations do IUE.

For close(), it's not such a problem of exiting unconditionaly
as if awk exits, even if the child process ignores/handle SIGINT,
it would either see eof on stdin or get a sigpipe the next time
it writes some output. 

Now the gawk system() behaviour may not seem ideal, but it has
the merit of allowing you do handle the CTRL-C in your awk
script, by doing something like:

awk '
 {
   ...
   ret = system("trap \"exit 3\" INT; trap \"exit 4\" QUIT; cmd")
   signal = ret == 3 ? "INT" : ret == 4 ? "QUIT" : 0
   if (signal) exit
   ...
 }
 END {
   if (signal) {
     cmd = "kill -s " signal " \"$PPID\""
     cmd | getline
     close(cmd)
     exit(255) # not meant to be reached
   }
   ...
 }'

Now, who's ever going to do that?

The thing is, that code above is what you'd like to see happen
by default most of the time. Either that or the WUE (awk
terminating on CTRL-C even when the system() command handles the
SIGINT).

WCE is probably the best compromise for system(). For getline
pipeline, I suspect implementing WCE would cause more problem
than help.

-- 
Stephane



reply via email to

[Prev in Thread] Current Thread [Next in Thread]