OS X sigaction incorrectly setting sa_mask
c, language-lawyer, macos, sigaction, sigprocmask
Solution
I would expect that the `sa_mask` member of `osa` to match `mask` as given by `sigprocmask`.
Your expectation is incorrect.
Here's a link to the current (as of this writing) official POSIX documentation. Bookmark it!
Here is what that documentation says about `sa_mask`:
Additional set of signals to be blocked during execution of signal-catching function.
There is no reason to expect `osa.sa_mask` to match `mask`. Your `mask` is the current signal mask. Your `osa.sa_mask` is an additional signal mask that would have been applied during a call to `osa.sa_handler` to handle a `SIGALRM`.
In your test case, `osa.sa_handler` is `SIG_DFL`, so the contents of `osa.sa_mask` is irrelevant. As far as I know (after a brief search), POSIX says nothing about what `osa.sa_mask` should be when, as in your test case, the process hasn't set an action for the signal since the most recent `exec`.
Furthermore, when the system calls an installed `SIGALRM` handler, it includes `SIGALRM` in the signal mask automatically (unless you passed `SA_NODEFER` or `SA_RESETHAND` when you installed the handler). Quoting the documentation linked above:
When a signal is caught by a signal-catching function installed by `sigaction()`, a new signal mask is calculated and installed for the duration of the signal-catching function (or until a call to either `sigprocmask()` or `sigsuspend()` is made). This mask is formed by taking the union of the current signal mask and the value of the `sa_mask` for the signal being delivered, and unless `SA_NODEFER` or `SA_RESETHAND` is set, then including the signal being delivered.
Thus it's irrelevant whether `sa_mask` includes `SIGALRM` if `sa_flags` is 0. The fact that Linux doesn't include it and OS X does makes no difference to the handling of the signal.
Note too that it's not clear (to me) that it's legal to pass 0 (instead of one of the defined constants) for the `how` argument of `sigprocmask`, even when the `set` argument is null. But I found that changing it to `SIG_BLOCK` made no difference.
Problem
On a macbook (OSX 10.9.5 (13F34)) the following simple program: ``` #include <stdio.h> #include <signal.h> static void nop(int unused) { } int main(void) { struct sigaction sa, osa; sigset_t mask; sigemptyset(&sa.sa_mask); printf("Errno after sigempty sa_mask: %d\n", errno); sigemptyset(&osa.sa_mask); printf("Errno after sigempty oldsa_mask: %d\n", errno); sa.sa_flags = 0; sa.sa_handler = nop; sigprocmask(0, NULL, &mask); printf("Errno after sigprocmask mask: %d\n", errno); printf("%d\n", sigismember(&mask, SIGALRM)); sigaction(SIGALRM, &sa, &osa); printf("Errno after sigaction sa osa: %d\n", errno); printf("%d\n", sigismember(&osa.sa_mask, SIGALRM)); printf("%d\n", sigismember(&sa.sa_mask, SIGALRM)); return 0; } ``` Mysteriously prints: ``` Errno after sigempty sa_mask: 0 Errno after sigempty oldsa_mask: 0 Errno after sigprocmask mask: 0 0 Errno after sigaction sa osa: 0 1 0 ``` I would expect that the `sa_mask` member of `osa` to match `mask` as given by `sigprocmask`. Does POSIX specify any requirements for this field? The only mention of it in the manpages is with regard to unblockable signals like `SIGKILL`, where that value is unspecified. On linux, this program prints: ``` Errno after sigempty sa_mask: 0 Errno after sigempty oldsa_mask: 0 Errno after sigprocmask mask: 0 0 Errno after sigaction sa osa: 0 0 0 ``` as expected. The gcc version is: ``` $ gcc --version Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1 Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn) Target: x86_64-apple-darw ``` The binary is linked against: ``` /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1) ```