简体   繁体   中英

sigprocmask during signal's execution

I'm currently researching using sigprocmask to block certain signals (in this case, SIGALRM and SIGCHLD ) when a critical segment of code is executing. Both of the signal handlers associated with these signals will access and modify a central data structure, so it is crucial that I prevent them from accessing it while the main process is working on it.

At the moment, my plan would be to simply disable these signals at the start of the critical section of code, and then re-enable them at the end.

void criticalFunction(void) {
    // disable signals with sigprocmask
    // critical code
    // enable signals with sigprocmask
}

However, the signal handler's for the signals which will be blocked also call criticalFunction . What will happen when they call the sigprocmask function and enable blocking on their own signals? Will they stall or keep executing? (Or some third condition..)

The only note I was able to find about this is the following:

If sigprocmask() is called in a signal handler, returning from the handler may undo the work of sigprocmask() by restoring the original pending signal mask. ( http://www.mkssoftware.com/docs/man3/sigprocmask.3.asp )

(This is a follow-up question to my previous question: Signal handler accessing queue data structure (race condition?) )

Keep in mind that the default behavior inside a signal-handler is to block the signal that is being handled. Also when making function calls inside of signal-handlers, you want to only call signal-safe functions. With that said, sigprocmask() is a signal-safe function , and if you are using it to block the same signal that is being blocked by the signal handler it's being called inside, then really nothing is going to happen ... you're going to remain with the same signal-mask that you currently have. The only difference is that inside the signal-handler, only the signals for either SIGALRM or SIGCHLD are guaranteed to be blocked (it will depend on which signal-handler you are in), where-as when you call sigprocmask() to block those specific signals, both signals will be blocked after the call.

The thing to watch out for is the second part of your code in criticalFunction when you try to call sigprocmask() to enable the signals that are currently blocked in the signal mask. What this could create is a situation where you end up with a level of re-entrancy in the calls to your signal handler. In other words enabling the signal for the signal-handler you're in can mean that before you exit from the current signal handler, another SIGALRM or SIGCHLD is caught, and you'll re-enter the signal-handler again to handle this newly caught signal. As long as you're enabling the signals after any critical-section updates, then I think you should be fine with this re-entrant situation, but just to play it safe, you may only want to enable the signals in criticalFunction at the very end of criticalFunction , not somewhere in the middle, and when you return from criticalFunction , don't do anything that would not be async-safe ... you have to assume that the any code after the return of the second sigprocmask() may not be executing in-order (ie, it might be executing after a second signal was caught and its signal-handler was run).

You would only need to be concerned about "stalling" if you tried to call something from the exec family, or something of that nature inside of your signal-handler. What would happen is that the newly overlaid process would inherit the signal-mask from the current process, so if the current process had blocked certain signals, then they would also be blocked in the new process. Thus if the new process was assuming the signals were unblocked, your signal-handler in the new process would never run.

BTW, one warning: don't mix signals and threads ! You mention "main process" in your question ... I hope that doesn't mean you're attempting to mix signals and threads. If so, that requires a very specific idiom, otherwise you will create all sorts of havoc.

Your design is wrong when you say that "signal handlers [...] call criticalFunction ." Signal handlers should never do any serious amount of work. They're not made for that.

The only thing you should reasonably do from within a signal handler is to modify a variable of type sigatomic_t . This is usually used to set a flag, and the remainder of your code (eg the main loop) just has to check periodically if any flags have been set.

I think it is in fact undefined behaviour if a signal handler does anything other than that. Update: From man 2 signal : "See signal(7) for a list of the async-signal-safe functions that can be safely called from inside a signal handler."

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM