Signal handling in C - interrupt in interrupt

。_饼干妹妹 提交于 2019-11-28 13:42:35

Quoting the sigaction(2) manpage:

Signal routines normally execute with the signal that caused their invocation blocked, but other signals may yet occur. A global signal mask defines the set of signals currently blocked from delivery to a process. The signal mask for a process is initialized from that of its parent (normally empty). It may be changed with a sigprocmask(2) call, or when a signal is delivered to the process.

You can control whether the signal is automatically blocked in its signal handler with the SA_NODEFER flag.

The order in which these particular pending signals are delivered is not, as far as I know, defined. However, signals are (mostly; there's an exception for SIGCLD, which is traditionally done by "cheating") "non-queueing", except for real-time signals. The non-queuing aspect means that if you have signal X blocked, and then raise it twice (as you do above for SIGUSR1), you only get it delivered once.

The only ordering documented on at least one system (MacOS) is:

If multiple signals are ready to be delivered at the same time, any signals that
could be caused by traps are delivered first.

(These are things like SIGSEGV and SIGBUS.) In general, you can control the order of delivery by use of the signal blocking masks: unblock any particular signal(s) at some point and those are the ones that can be delivered at that point.

If you do not set SA_NODEFER, the blocking mask at the entry to your handler will always block whatever signal your handler is handling, so that you won't have to worry about recursion.

The special case for SIGCLD comes from System V, which originally implemented this by resetting the handler to SIG_DFL on each SIGCLD delivery. (In fact, SysV did this with all signals, effectively implementing SA_RESETHAND whether you wanted it or not.) The default action was to discard the signal, as if the handler were SIG_IGN. This of course created race conditions when multiple child processes finished before the handler could do its thing. Instead of a block/unblock model, though, the SysV folks put in a hack: at the end of your SIGCLD handler, you would call signal(SIGCLD, handler); to fix up the handler. At that point, if there were any exited children that had not yet been wait-ed for, SysV would immediately generate a new SIGCLD, and your handler would be entered recursively. This made it look as though the signals were queued, without actually queueing them.

For more on Linux signals, see (eg) http://www.kernel.org/doc/man-pages/online/pages/man7/signal.7.html.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!