OS X sigaction incorrectly sets sa_mask
On macbook (OSX 10.9.5 (13F34)) the following is a 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 the member sa_mask
osa
to match mask
as given sigprocmask
.
Does POSIX specify any requirements for this field? The only mention of this in the manpages is for non-blocking signals, such as SIGKILL
where this value is not specified.
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 was expected.
Gcc version:
$ 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 associated with:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)
source to share
I would expect the member
sa_mask
osa
to matchmask
as givensigprocmask
.
Your expectation is wrong.
Here's a link to the current (at the moment) official POSIX documentation . Bookmark!
Here's what the documentation says sa_mask
:
An additional set of signals to be blocked during the signal capture function.
There is no reason to expect it osa.sa_mask
to match mask
. Yours mask
is the signal mask current . Yours osa.sa_mask
is an additional signaling mask that would be applied during the call osa.sa_handler
for processing SIGALRM
.
In your test case osa.sa_handler
there is SIG_DFL
, so the content osa.sa_mask
doesn't matter. As far as I know (after a short search), POSIX says nothing about what should be osa.sa_mask
when, as in your test case, the process has not set an action for the signal since the very last exec
.
In addition, when the system calls the installed handler SIGALRM
, it automatically includes the SIGALRM
signal mask (if you have not passed SA_NODEFER
or SA_RESETHAND
when installing the handler). To quote the above documentation:
When a signal is captured by the signal capture function set
sigaction()
, a new signal mask is calculated and set for the duration of the signal capture function (or before calling eithersigprocmask()
orsigsuspend()
). This mask is formed by combining the mask of the current signal and the valuesa_mask
for the transmitted signal, and if not set toSA_NODEFER
orSA_RESETHAND
, then including the transmitted signal.
So it doesn't matter if it includes sa_mask
SIGALRM
, if sa_flags
is 0. The fact that Linux doesn't include it and OS X has nothing to do with signal processing.
Note also that it is not clear (to me) that it is legal to pass 0 (instead of one of the defined constants) for an argument how
sigprocmask
, even if the argument set
is zero. But I found that changing it to SIG_BLOCK
didn't matter.
source to share