Вопрос по c – Обработка сигналов в C - прерывание в прерывании

5

Мне было интересно, можно ли прервать сигнал, когда моя программа обрабатывает другой сигнал одновременно, я попытался смоделировать его с помощью:

<code>#include<signal.h>
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<string.h>

void sig_output()
{
    sigset_t set;
    sigprocmask(0,NULL,&set);
    printf("currently blocking:");
    if (sigismember(&set,SIGUSR1))
        printf("\nSIGUSR1");
    if(sigismember(&set,SIGUSR2))
        printf("\nSIGUSR2");
    printf("\n");
    return ;
}

void sig_handler(int sig)
{
    raise(SIGUSR1);    
    printf("start\n");
    if (sig==SIGUSR1)
        printf("SIGUSR1\n");
    else if (sig==SIGUSR2)
        printf("SIGUSR2\n");
    printf("end\n");
    return ;
}

void other_sig_handler(int sig)
{  
    printf("start - other\n");
    if (sig==SIGUSR1)
        printf("SIGUSR1\n");
    else if (sig==SIGUSR2)
        printf("SIGUSR2\n");
    printf("end - other\n");
    return ;
}

int main()
{
    sig_output();
    struct sigaction a;
    a.sa_handler=sig_handler;
    a.sa_flags=0;
    sigset_t set,old;
    //blocking SIGUSR1,SIGUSR2
    sigemptyset(&set);
    sigaddset(&set,SIGUSR1);
    sigaddset(&set,SIGUSR2);
    printf("blocking SIGUSR1, SIGUSR2\n");
    sigprocmask(SIG_SETMASK,&set,&old);
    sig_output();
    //adding handles for SIGUSR1,SIGUSR2
    sigemptyset(&(a.sa_mask));
    sigaction(SIGUSR1,&a,NULL);
    a.sa_handler=other_sig_handler;
    sigaction(SIGUSR2,&a,NULL);
    printf("poczatek wysylania \n");
    raise(SIGUSR1);
    raise(SIGUSR2);
    raise(SIGUSR1);
    printf("using sigsuspend\n");
    sigsuspend(&old);
    printf("end of program\n");
    return 0;
}
</code>

и каждый раз, когда я запускаю эту программу, я получаю

<code>currently blocking:
blocking SIGUSR1, SIGUSR2
currently blocking:
SIGUSR1
SIGUSR2
raising
using sigsuspend
start - other
SIGUSR2
end - other
start
SIGUSR1
end
end of program
</code>

это всегда так?

Это зависит от процессора и ОС. Как правило, многие процессоры поддерживают разные уровни приоритета для прерываний, так что прерывание с более высоким приоритетом может появиться, в то время как работает более низкий приоритет. TJD
игналы @POSIX не являются аппаратными прерываниями, поэтому сам процессор здесь не обсуждается. torek

Ваш Ответ

2   ответа
6

sigaction(2) manpage:

роцедуры @Signal обычно выполняются с сигналом, вызвавшим блокировку их вызова, но другие сигналы могут все же возникнуть. Глобальная маска сигналов определяет набор сигналов, в настоящее время заблокированных от доставки в процесс. Маска сигнала для процесса инициализируется от маски его родителя (обычно пустой). Может быть изменено с помощьюsigprocmask(2) вызов или когда сигнал доставляется в процесс.

Вы можете контролировать, будет ли сигнал автоматически блокироваться в обработчике сигнала с помощьюSA_NODEFER флаг.

Ладно, я пропустил эту информацию. Andna
Стоит также отметить (я думаю, это не ясно из документации, хотя этоявляетс вполне логично) чsa_mask вы поставляете наsigaction это маска Дополнительная сигналы для блокировки, а не новая маска для установки. Так что если вы (1) попросите поймать сигнал X сsa_mask, который явно блокирует сигнал Y (и неявно блокирует X, потому что вы оставляетеSA_NODEFER off), затем (2) используйтеsigprocmask, чтобы заблокировать сигнал Z, то (3) фактически поймает сигнал X, ваш обработчик работает с заблокированными всеми X, Y и Z. torek
Это может быть непонятно из документации Linux; документация по OS X (через FreeBSD) довольно ясно показывает, как формируется новая маска. geekosaur
6

порядок доставки этих конкретных ожидающих сигналов не определен. Однако сигналыявляютс (в основном; есть исключение дляSIGCLD, что традиционно делается путем «обмана») «без очереди», за исключением сигналов реального времени. Аспект без очереди означает, что если у вас есть сигнал X заблокирован, а затемraise это дважды (как вы делали выше дляSIGUSR1), вы получите его только один раз.

Единственный заказ, документированный по крайней мере в одной системе (MacOS):

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

(Это такие вещи, какSIGSEGV а такжеSIGBUS.) В общем, вы можете контролировать порядок доставки с помощью масок блокировки сигнала: разблокируйте любой конкретный сигнал (сигналы) в некоторой точке, и это те, которые могут быть доставлены в этой точке.

Если ты не поставилSA_NODEFER, маска блокировки на входе в ваш обработчик всегда будет блокировать любой сигнал, который обрабатывает ваш обработчик, так что вам не придется беспокоиться о рекурсии.

Особый случай дляSIGCLD происходит из System V, которая изначально реализовала это путем сброса обработчика наSIG_DFL на каждогоSIGCLD Доставка. (На самом деле, SysV сделал это со всеми сигналами, эффективно реализуяSA_RESETHAND хочешь ты этого или нет.) Действие по умолчанию - сбросить сигнал, как если бы обработчик былSIG_IGN. Это, конечно, создало условия гонки, когда несколько дочерних процессов закончили, прежде чем обработчик смог сделать свое дело. Однако вместо блочной / разблокированной модели люди из SysV взломали: в конце вашегоSIGCLD Хендлер, ты бы позвонилsignal(SIGCLD, handler); чтобы исправить обработчик. В этот момент, если бы были какие-то возбужденные дети, которые еще не былиwait -ed для SysV немедленно сгенерирует Новый SIGCLD, и ваш обработчик будет введен рекурсивно. Это выглядело так, как будто сигналы были поставлены в очередь, фактически не ставя их в очередь.

Подробнее о сигналах Linux см. (Например)http: //www.kernel.org/doc/man-pages/online/pages/man7/signal.7.htm.

Похожие вопросы