dce@Solbourne.COM (David Elliott) (04/23/89)
I have an interesting problem. I have a program that runs attached to
the terminal, and it runs shell scripts underneath. The shell script
and the parent communicate via pipes, and the most common situation is
for the shell script to be executing a "read" command, waiting for the
parent to send down a response (usually as a result of the user
typing).
I have things set up such that if the shell script quits, the parent
knows this and quits, and if the parent quits gracefully, it tells the
shell script to quit as well.
The problem case is where the parent doesn't terminate gracefully, such
as when it dumps core or when I quit from under the debugger. In this
case, the shell script just sits in read forever.
Is there a way for the shell script to detect that this has happened
and quit? Obviously, this is out of the realm of a SIGPIPE trap, since
that means that you are writing to a pipe with no one to read it, and I
know of no SIGPARENT.
One idea I came up with was to change the read loop to something like
checkparent()
{
if kill -0 "$PPID" 2>/dev/null
then
(sleep 30 ; kill -12 $$) &
return
fi
exit 1
}
while
...
trap "checkparent" 12
(sleep 30 ; kill -12 $$) &
read event
trap "" 12
do
...
done
Basically, this traps for signal 12 (which is SIGSYS; I chose it
because it's not likely in this case) and fires off a process to sleep
for a while and then "spring" the trap. The function "checkparent"
checks to see if the parent process (whose id can be passed to the
shell script) is still alive, and if not forces the shell script to
exit. If the parent is alive, it resets the trap and returns so that
the read can complete.
Can anyone think of an easier method for checking this, or a way to
have the shell script just killed when the parent goes away?
--
David Elliott dce@Solbourne.COM
...!{boulder,nbires,sun}!stan!dce
bill@twwells.uucp (T. William Wells) (04/23/89)
Try enabling SIGPIPE in your parent before calling the shell script. When the parent dies, the children trying to read from pipes set up by the parent should then get a signal. You might have to use a trap command in the shells, though. --- Bill { uunet | novavax } !twwells!bill
dce@Solbourne.COM (David Elliott) (04/24/89)
In article <849@twwells.uucp> bill@twwells.UUCP (T. William Wells) writes: >Try enabling SIGPIPE in your parent before calling the shell script. >When the parent dies, the children trying to read from pipes set up >by the parent should then get a signal. You might have to use a trap >command in the shells, though. Are you sure about this? SIGPIPE *is* "enabled" in the parent (I just checked). Generally, when you execute a program interactively, all signals are set to SIG_DFL. Also, SIGPIPE is not a special case, so the default for it is to cause the program to terminate. In any case, SIGPIPE means that an attempt was made to write on a pipe with noone to read it, and that's not what is happening here (I did say that in the original note, I think). This is a situation where a read is being attempted on a pipe with noone on the other side. I would think this would cause an EOF, and there was some discussion on this recently, but it doesn't. -- David Elliott dce@Solbourne.COM ...!{boulder,nbires,sun}!stan!dce
ka@june.cs.washington.edu (Kenneth Almquist) (04/26/89)
dce@Solbourne.COM (David Elliott) writes: > [A] read is being attempted on a pipe with [no one] on the other > side. I would think this would cause an EOF, and there was some > discussion on this recently, but it doesn't. It does cause an EOF, unless your UNIX is broken (which is unlikely). Probably you are forgetting to close the other end of the pipe. The way to set up a pipe to a child process (exclusive of error checking) is: pipe(pip); if (fork() == 0) { --> close(pip[1]); runchild(pip[0]); exit(0); } close(pip[0]); ... If you leave out the line that I've marked with an arrow, the child process will have both ends of the pipe open, so even when the parent terminates the child still won't get an EOF when it reads from the pipe. Kenneth Almquist
bill@twwells.uucp (T. William Wells) (04/26/89)
In article <866@marvin.Solbourne.COM> dce@Solbourne.com (David Elliott) writes: : In article <849@twwells.uucp> bill@twwells.UUCP (T. William Wells) writes: : >[something stupid]. : : Are you sure about this? No. I have no idea what drugs I had been slipped when I wrote that. Or maybe it's lack of sleep? :-) : I would think this would cause an EOF, and there was some : discussion on this recently, but it doesn't. So would I. And, in fact it does. The problem is that the shell doesn't exit on EOF. I just tested this on my V/386 3.0 Bourne shell. I wrote a little shell: while true do read foo echo "<$foo>" done to see what happens. And what happens is that EOF and newline both set foo to a null string. HEY! I just RTFM. According to it, you get a return status from read! Adding: echo $? before the other echo, I get 0 on a blank line, 1 on EOF. When I feed data through a pipe, it works as expected. (I feel better now I can wipe the egg off my face.) --- Bill { uunet | novavax } !twwells!bill
dce@Solbourne.COM (David Elliott) (04/27/89)
Thanks to all who responded. It was indeed a case of me not closing the other ends of the pipes in the child. I now get an EOF as expected. -- David Elliott dce@Solbourne.COM ...!{boulder,nbires,sun}!stan!dce
steve@nuchat.UUCP (Steve Nuchia) (04/28/89)
In article <869@twwells.uucp> bill@twwells.UUCP (T. William Wells) writes: > while true > do > read foo > echo "<$foo>" > done >to see what happens. And what happens is that EOF and newline both >set foo to a null string. Try this one: while read foo do echo $foo done -- Steve Nuchia South Coast Computing Services uunet!nuchat!steve POB 890952 Houston, Texas 77289 (713) 964 2462 Consultation & Systems, Support for PD Software.