1

I'm trying to deal with a server that works as follows:

  • It has a parent process
  • It creates a "helper" child process to handles some special tasks
    • It opens the child process with a pipe; and uses the pipe to issue commands to the child.
  • It also spawns off many other child processes (the server's main goal is to execute various commands).

I would like to be able to detect when the write to the pipe to the child process fails; and issue a special notification.

Ordinarily, I would achieve that by creating a custom $SIG{PIPE} handler in the parent process.

However, what I'm concerned with is the fact that some of the processes the parent launches to execute commands might have their own pipes open to them; and if the write to THOSE pipes fails, I'd like to simply ignore the SIGPIPE.

Q1. Is there a way for me to tell from within SIGPIPE handler, which of the open pipes threw the signal? (I know every child's PID, so PID would be fine... or if there's a way to do it via file descriptor #s?).

Q2. Could I solve the problem using local $SIG{PIPE} somehow? My assumption is that I would need to:

  • Set helper-process-specific local $SIG{PIPE} right before writing to that pipe
  • do print $HELPER_PIPE (this happens in only one subroutine)
  • Reset $SIG{PIPE} to DEFAULT or IGNORE
  • Ensure that these 3 actions are within their own block scope.
ikegami
  • 367,544
  • 15
  • 269
  • 518
DVK
  • 126,886
  • 32
  • 213
  • 327
  • Not sure what you are using to write the command, but if the write fails `perldoc -f syswrite`, should it not return 'undef' and since you know which child you are writing too, seems easier to detect the failure in the write call then worry about the signals which looks fraught with peril. – mikew Mar 29 '14 at 01:36
  • @mikew - as my bullet points indicate, a simple `print $PIPE "string"`. Also, I will be detecting return from write call as well – DVK Mar 29 '14 at 01:37
  • What's "them" in "might have their own pipes open to them"? – ikegami Mar 29 '14 at 04:19

2 Answers2

5

The write syscall returns the error EPIPE in the same case when a SIGPIPE is triggered, assuming that the SIGPIPE doesn't succeed in killing the process. So your best bet is to set $SIG{PIPE} = 'IGNORE' (to avoid dying from the signal), to use $fh->autoflush (to avoid PerlIO buffering, ensuring that you're notified of any I/O errors immediately), and to check the return value of print whenever you call it. If print returns false and $!{EPIPE} is set, then you've tried to write to a closed pipe. If print returns false and $!{EPIPE} isn't set, you have some other issue to deal with.

ikegami
  • 367,544
  • 15
  • 269
  • 518
hobbs
  • 223,387
  • 19
  • 210
  • 288
3

Portably you can't tell. However, you might find your OS supports the SIG_INFO information, and if you can get that up to Perl somehow, the siginfo structure contains a field that gives the FD number on SIGPIPE.

LeoNerd
  • 8,344
  • 1
  • 29
  • 36
  • To save others, From C I find this si_fd field contains nothing useful fro SIGPIPE. It is intended for SIGPOLL. si_fd is actually a field in the union substruct _sigpoll. – Gem Taylor Jul 29 '19 at 17:46