Reputation: 6948
I got some code that prints to stdout, in pseudo code it looks like
int main(){
//allocate data
while(conditional){
char *string = makedata();
fprintf(stdout,"%s",string);
}
//cleanup
}
This works fine, if the conditional is toggled to zero, but if I pipe the output like
./a.out |head -n10 >dumped
Then the code never reaches the cleanup part, I don't understand how to check if the stdout gets closed.
Thanks
Upvotes: 7
Views: 3903
Reputation: 168626
Your stdout hasn't been closed, so checking for that will be useless. Your program has received a SIGPIPE and exited. A SIGPIPE is delivered whenever your program writes to a pipe on which there are no readers. In your example, that happens when head
exits, closing its stdin.
You should ignore SIGPIPE if you want your program to continue. This code will ignore SIGPIPE:
(void)signal(SIGPIPE, SIG_IGN);
If you don't want to modify your program, you can arrange that something continues to read from the pipe, even after head
closes its input. 1
./a.out | ( head -n10 >dumped ; cat > /dev/null )
1: The shell example is valid for bash, maybe not for csh.
Upvotes: 5
Reputation: 212248
As Rob points out in comments to his answer, you are not worried that stdout has been closed; rather, you are worried that the other end of the pipe is closed. This may be pedantry, but it leads to the solution of your problem. Namely, you do not care if stdout is closed, but only if your printf succeeds. You should check the return value of printf: if it is -1, then the write has failed.
As Simon Richter points out, you will never get the return value of printf if you do not ignore SIGPIPE, because a result of writing to stdout when the other side of the pipe has been closed is that SIG_PIPE will be sent to the process. So you need to do something like:
signal( SIGPIPE, SIG_IGN ); /* Careful: you now must check the return of *all* writes */ if( fprintf( stdout, ... ) == -1 ) { /* handle the error */ }
Upvotes: 1
Reputation: 29586
It is closed by killing the process with SIGPIPE
.
If you want to go on when your output is being ignored, then set up a SIG_IGN
handler for SIGPIPE
, and handle the error from the fprintf
(which will be delayed by buffering, so you cannot assume data that has been written has actually reached the user).
Upvotes: 3
Reputation: 14057
I've not tried this, but provided you were using the standard file descriptor for stdout, you may be able to try performing an fstat(1, &stat_structure) and check the return and error codes.
Upvotes: 0