OS X sigaction неправильно устанавливает sa_mask

На macbook (OSX 10.9.5 (13F34)) следующая простая программа:

#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;
}

Таинственно печатает:

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

Я ожидаю, что sa_mask член osa соответствовать mask как указано sigprocmask,

POSIX определяет какие-либо требования для этого поля? Единственное упоминание об этом в man-страницах в отношении таких неблокируемых сигналов, как SIGKILLгде это значение не указано.

На Linux эта программа печатает:

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

как и ожидалось.

Версия gcc:

$ 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

Двоичный файл связан с:

/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)

1 ответ

Решение

Я ожидаю, что sa_mask член osa соответствовать mask как указано sigprocmask,

Ваше ожидание неверно.

Вот ссылка на текущую (на момент написания) официальную документацию POSIX. Закладка это!

Вот что говорится в этой документации sa_mask :

Дополнительный набор сигналов, блокируемых во время выполнения функции захвата сигналов.

Нет причин ожидать osa.sa_mask соответствовать mask, Ваш mask текущая маска сигнала. Ваш osa.sa_mask дополнительная маска сигнала, которая была бы применена во время вызова osa.sa_handler обращаться с SIGALRM,

В вашем тестовом случае osa.sa_handler является SIG_DFL, так что содержание osa.sa_mask не имеет значения. Насколько я знаю (после непродолжительного поиска), POSIX ничего не говорит о том, что osa.sa_mask должно быть, когда, как в вашем тестовом примере, процесс не установил действие для сигнала с самого последнего exec,

Кроме того, когда система вызывает установленный SIGALRM обработчик, включает в себя SIGALRM в маске сигнала автоматически (если вы не прошли SA_NODEFER или же SA_RESETHAND когда вы установили обработчик). Цитирование документации, связанной выше:

Когда сигнал улавливается функцией захвата сигнала, установленной sigaction() новая маска сигнала вычисляется и устанавливается на время действия функции перехвата сигнала (или до вызова sigprocmask() или же sigsuspend() сделан). Эта маска формируется путем объединения маски текущего сигнала и значения sa_mask для доставляемого сигнала, и если SA_NODEFER или же SA_RESETHAND устанавливается, затем включая сигнал, который доставляется.

Таким образом, не имеет значения, sa_mask включает в себя SIGALRM если sa_flags равно 0. Тот факт, что Linux не включает его, а OS X не имеет никакого значения для обработки сигнала.

Заметьте также, что не ясно (для меня), что допустимо передавать 0 (вместо одной из определенных констант) для how аргумент sigprocmask даже когда set аргумент нулевой. Но я обнаружил, что меняя его на SIG_BLOCK не имеет значения.

Другие вопросы по тегам