2012-04-10 3 views
5

я задавался вопросом, если это возможно, будет прерван сигналом, когда моя программа обработки другого сигнала в то же время, я пытался имитировать его:Обработка сигналов в C - прерывание в режиме прерывания

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

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

currently blocking: 
blocking SIGUSR1, SIGUSR2 
currently blocking: 
SIGUSR1 
SIGUSR2 
raising 
using sigsuspend 
start - other 
SIGUSR2 
end - other 
start 
SIGUSR1 
end 
end of program 

Всегда ли это так?

+0

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

+5

Сигналы POSIX не являются аппаратными прерываниями, поэтому сам процессор здесь не ставится под сомнение. – torek

ответ

6

Цитируя sigaction(2): справочная страницы

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

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

+0

Хорошо, я должен пропустить эту информацию. – Andna

+1

Также стоит отметить (я думаю, что это не ясно из документации, хотя это * вполне логично), что 'sa_mask', который вы передаете' sigaction', является маской * дополнительных * сигналов для блокировки, а не новой маской для задавать. Поэтому, если вы (1) попросите поймать сигнал X с помощью 'sa_mask', который явно блокирует сигнал Y (и неявно блокирует X, потому что вы оставляете' SA_NODEFER' выключен), тогда (2) используйте 'sigprocmask' для блокировки сигнала Z, затем (3) на самом деле поймать сигнал X, ваш обработчик работает со всеми заблокированными X, Y и Z. – torek

+0

Это может быть неясно из документации Linux; Документация OS X (через FreeBSD) довольно понятна о том, как формируется новая маска. – geekosaur

5

Порядок, в котором эти конкретные ожидающие сигналы доставляются, не определен, насколько я знаю. Однако сигналы : (в основном, есть исключение для 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 исходит из системы V, которая изначально была реализована, путем сброса обработчика на SIG_DFL на каждую доставку SIGCLD. (Фактически, SysV делал это со всеми сигналами, эффективно применяя SA_RESETHAND независимо от того, хотите ли вы этого или нет.) Действие по умолчанию состояло в том, чтобы отбросить сигнал, как если бы обработчик был SIG_IGN. Это, конечно, создало условия гонки, когда несколько дочерних процессов завершили работу до того, как обработчик мог выполнить свою задачу. Вместо модели block/unblock люди SysV помещаются в хак: в конце вашего обработчика SIGCLD вы должны позвонить signal(SIGCLD, handler);, чтобы исправить обработчик. В этот момент, если бы были какие-либо из детей, которые еще не были зарегистрированы wait, SysV немедленно сгенерировал новыйSIGCLD, и ваш обработчик будет введен рекурсивно. Это заставило его выглядеть так, как если бы сигналы были поставлены в очередь, фактически не поставив их в очередь.

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

Смежные вопросы