views:

1141

answers:

3

When you pipe two process and kill the one at the "output" of the pipe, the first process used to receive the "Broken Pipe" signal, which usually terminated it aswell. E.g. running

$> do_something_intensive | less

and then exiting less used to return you immediately to a responsive shell, on a SuSE8 or former releases. when i'm trying that today, *do_something_intensive* is obviously still running until i kill it manually. It seems that something has changed (glib ? shell ?) that makes program ignore "broken pipes" ...

Anyone of you has hints on this ? how to restore the former behaviour ? why it has been changed (or why it always existed multiple semantics) ?

edit : further tests (using strace) reveal that "SIGPIPE" is generated, but that the program is not interrupted. A simple

#include <stdio.h>
int main() 
{
   while(1) printf("dumb test\n");
   exit(0);
}

will go on with an endless

--- SIGPIPE (Broken pipe) @ 0 (0) ---
write(1, "dumb test\ndumb test\ndumb test\ndu"..., 1024) = -1 EPIPE (Broken pipe)

when less is killed. I could for sure program a signal handler in my program and ensure it terminates, but i'm more looking for some environment variable or a shell option that would force programs to terminate on SIGPIPE

edit again: it seems to be a tcsh-specific issue (bash handles it properly) and terminal-dependent (Eterm 0.9.4)

+4  A: 

Well, if there is an attempt to write to a pipe after the reader has gone away, a SIGPIPE signal gets generated. The application has the ability to catch this signal, but if it doesn't, the process is killed.

The SIGPIPE won't be generated until the calling process attempts to write, so if there's no more output, it won't be generated.

Daniel Papasian
+2  A: 

Has "do something intensive" changed at all?

As Daniel has mentioned SIGPIPE is not a magic "your pipe went away" signal but rather a "nice try, you can no longer read/write that pipe" signal.

If you have control of "do something intensive" you could change it to write out some "progress indicator" output as it spins. This would raise the SIGPIPE in a timely fashion.

Frosty
about do_something_intensive:if i'm doing "yes | less" and terminate 'less', "yes" receives a SIGPIPE and terminates.if instead i'm doing "objdump -drS ... | less", "objdump" goes on (despite strace reveals reapeated SIGPIPEs); so does a dumb loop doing "printf".
sylvainulg
A: 

Thanks for your advices, the solution is getting closer...

According to the manpage of tcsh, "non-login shells inherit the terminate behavior from their parents. Other signals have the values which the shell inherited from its parent."

Which suggest my terminal is actually the root of the problem ... if it ignored SIGPIPE, the shell itself will ignore SIGPIPE as well ...

edit: i have the definitive confirmation that the problem only arise with Eterm+tcsh and found a suspiciously missing signal(SIGPIPE,SIG_DFL) in Eterm source code. I think that close the case.

sylvainulg
I remember from way back that quitting a csh shell with backgrouynd jobs allowed the jobs to carry on running, but quitting a bash(ksh) shell would kill any non nohup-ed jobs.
dsm