信号的表示

我们知道linux下,可以通过kill命令向进程发送信号.

当进程收到信号,执行处理动作被称为递达;

当进程接收到信号,还未来得及处理被称之为未决(pending);

进程可以选择阻塞某个信号,当某个信号被阻塞(block)时,永远不会递达!

因此,与这三种处理相对应,在进程的pcb中,存在三张位图来描述信号相关信息!

block、pending与handler

block是一个位图,如果某个信号block为1,则表示其永远也不会递达,也就是说永远都不会执行handler表中的函数.

pending也是一个位图,如果某个信号pending为1,表示其已经产生,如果为0,表示没有产生.

handler指针数组,表示某个信号处理时的默认动作,SIG_DFL表示默认处理,SIG_IGN表示忽略该信号,其它表示自定义处理.

信号的屏蔽与恢复

知道了这些,我编写了一个程序,来验证一下屏蔽、恢复屏蔽一个信号.

////////////////////////////////////
//文件说明:pending.c
//作者:高小调
//创建时间:2017年06月28日 星期三 15时15分45秒
//开发环境:Kali Linux/g++ v6.3.0
////////////////////////////////////
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
//屏蔽SIGINT
void blockSIGINT(){
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set,SIGINT);
    sigprocmask(SIG_BLOCK,&set,NULL);
}
//恢复SIGINT
void recoverSIGINT(){
    sigset_t set;
    sigemptyset(&set);
    sigprocmask(SIG_SETMASK,&set,NULL);
}
//打印未决表
void printPending(sigset_t *set){
    for(int i=1; i<=31; ++i){
        if(sigismember(set,i)){
            putchar('1');
        }else{
            putchar('0');
        }
    }
    putchar('\n');
}
void handler(int sig){
    printf("the No.%d signal is deliver!\n",sig);
}
int main(){
    signal(SIGINT,handler);
    int count = 5;
    printf("block the SIGINT %ds later!\n",count);
    sigset_t set;
    sigemptyset(&set);
    //先将SIGINT屏蔽掉
    while(1){
        if(count==0){
            blockSIGINT();
            printf("SIGINT has benn blocked!\n");
            break;
        }
        sigpending(&set);
        printPending(&set);
        sleep(1);
        --count;
    }
    //再把它恢复过来
    printf("recover the SIGINT %ds later!\n",10-count);
    while(1){
        if(count==10){
            recoverSIGINT();
            printf("SIGINT has been recovered!\n");
            break;
        }
        //恢复之前,信号被阻塞,因此如果产生SIGINT信号,将会处于未决状态
        sigpending(&set);
        printPending(&set);
        count++;
        sleep(1);
    }
    while(1);
    return 0;
}