top | item 20227830

(no title)

jforberg | 6 years ago

This is true, but if anything it reinforces my point that continuing past a signal is the exception, not the rule.

In the general case services are not at liberty to just exit(), they need to perform some kind of active cleanup action before exit. So the signal handler would set an "exit flag" somewhere and the EINTR would be an indication for the main loop to check this flag before continuing.

The only common case I can think to continue past signals is SIGHUP, which some services interpret as a command to re-read their configuration file. In this case, you are essentially doing a shutdown and startup sequence anyway, only in a possibly more efficient way. E.g. the case of a web server, if you were previously listening on port N there's no reason to believe that the new config file won't ask you to instead listen on port M. So you will be closing down most connections anyway, and catching SIGHUP is mostly an optimisation as exiting and restarting would have a similar effect.

discuss

order

abbeyj|6 years ago

For continuing past signals, what about SIGCHLD? I don't think anybody wants that to kill their process.

Most programs are also going to want SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, and SIGCONT to be handled transparently with the process continuing on as if nothing happened. I've actually been bitten by this. I had written a program that worked fine on Linux. While it was waiting for input on stdin you could suspend it with Ctrl-Z and then resume it with `fg`. When my friend tried this on his machine (a Mac, IIRC), it would suspend fine. Then resuming it would cause it to immediately die with "Interrupted system call". I hadn't written any code to handle EINTR. I'd been getting away with it because something in glibc and/or the kernel were helping me out and hiding this detail for me.

After a SIGWINCH or a SIGINFO you probably want to continue on too. If you've registered a handler for SIGUSR1 and/or SIGUSR2 you usually don't shut down after receiving them.

SIGPIPE is arguable. If you've decided to handle broken pipes by looking for errno == EPIPE then you likely want SIGPIPE to be ignored entirely, as if it had never happened. But you have to opt into this behavior by explicitly setting SIGPIPE to be ignored. The default behavior is to terminate your process.

For SIGALRM you probably do want a system call to be interrupted and return EINTR. But that usually doesn't indicate that your program will quit but that you wanted a timeout on some operation and that you intend to continue on with other work in the case that it didn't complete quickly.

The issue here is that signals have a bunch of different behaviors shoehorned into them. There are things like SIGSEGV and SIGBUS that need to be handled synchronously because they related to the current instruction. There are things like SIGINT, SIGINFO, and SIGTSTP that come from user action on the terminal. There are things like SIGCHLD that are generated by the kernel in response to events on the system. And there are things like SIGTERM and SIGUSR1 that are generated by a different process calling kill(2). Trying to make blanket statements about all of them is tricky.