Linux——信号知识归纳(中)

目录

一.信号与硬件异常

二.阻塞信号和信号结构

(一).信号状态

(二).信号结构

①pending表

②block表

③handler表

(三).信号处理过程

(四).阻塞与忽略的区别

(五).不可阻塞和自定义的信号

三.信号函数

①sigpending

②sigprocmask

③sigemptyset

④sigfillset

⑤sigaddset

⑥sigdelset

⑦sigismember

⑧使用示例


一.信号与硬件异常

硬件产生异常并使程序崩溃的方式有很多,比如除0错误、空指针、数组越界等。

大致上,当硬件产生异常后,会“汇报”给操作系统,再由操作系统发送相关信号给进程,促使进程异常退出。

以除0错误为例,当cpu检测到除0后,其中状态寄存器会标记异常,操作系统识别到该寄存器标记了异常后,发送信号给当前进程,进而进程崩溃退出。

再比如空指针问题,当虚拟地址为空时,页表通过MMU(硬件)映射时会出错,MMU内部寄存器会标记异常,操作系统识别后发送信号给进程,进程崩溃退出。

二.阻塞信号和信号结构

(一).信号状态

信号在发送过程中有三种状态:未决、递达、阻塞

状态 含义
信号未决 信号产生后,进程接收但未执行具体方法
信号递达 执行信号方法的状态或正在处理信号
信号阻塞 进程收到信号,但不允许递达,即不允许处理信号

如果某信号处于阻塞态,那么该信号将无法调用对应的信号函数。

(二).信号结构

首先,我们需要知道的是,信号在操作系统中以位图的形式记录,普通信号是1 - 31,正好可以使用位图对照,0代表进程此时没收到该信号,1代表收到该信号。

实际上,linux的信号有三个信号表构成,即pending表、block表、handler表

这三个表属于进程PCB结构体,记录在task_struct中。

①pending表

该表本质上是一个位图结构,记录进程是否收到该位对应的信号。0代表没有收到,1代表收到。

②block表

该表也是位图结构,每一位记载该信号是否阻塞,0代表未阻塞,1代表阻塞。

③handler表

该表是函数指针数组,数组每一个下标对应一个信号,每个下标对应的指针指向该信号的处理函数。

SIG_IGN表示处理方式为忽略。

SIG_DFL表示处理方式为默认。

比如2号信号使用默认函数可以表示为:

signal(SIGINT, SIG_IGN);

(三).信号处理过程

(四).阻塞与忽略的区别

阻塞是进程接收信号后,“故意”不执行方法。

忽略是进行接收信号后,执行了方法,但方法是忽略。

本质上,阻塞是将block表该位置1;忽略的该位为0,在handler表中记载的是SIG_IGN。

(五).不可阻塞和自定义的信号

9号信号SIGKILL、18号信号SIGCONT、19号信号SIGSTOP不可被阻塞和自定义。

换句话说,即便是手动添加阻塞信号或自定义处理方法也是无效的,依旧执行默认的方法。

三.信号函数

①sigpending

用于获取当前进程的pending表。

 操作系统中定义了sigset_t类型的数据,按位图的形式保存信号,即信号集。 

 第一个参数是输出型参数,通过该函数获得当前进程的pending位图。

返回值0代表获取成功,-1代表获取失败。

②sigprocmask

用于改变阻塞信号

 第一个参数有三个可选项:

选项 含义 操作
SIG_BLOCK set中所有置1的都设置成阻塞 block = block | set
SIG_UNBLOCK set中所有置1的都设置成非阻塞 block = block & ~set
SIG_SETMASK 进程block位图表与set表一致 block = set

第二个参数是输入型参数,用于确定哪些位阻塞/解除阻塞

第三个参数是输出型参数,获取旧的block位图表。

返回值含义与sigpending一致。

③sigemptyset

用于将信号集全部置0

参数为输出型参数,set内各位将置为0。

返回值含义与sigpending一致。

④sigfillset

用于将信号集全部置1

参数为输出型参数,set内各位将置为1。

返回值含义与sigpending一致。

⑤sigaddset

用于将信号集某一位设置为1

 第一个参数为输出型参数,set中指定位将置1。

第二个参数为指定的信号值。

返回值含义与sigpending一致。

⑥sigdelset

用于将信号集某一位设置为0

 参数和返回值含义与sigdelset相同,唯一不同就是该位设置为0。

⑦sigismember

用于确定信号集特定位的数值

 第一个参数为输入型参数,输入的待查看的信号集。

第二个参数为指定的信号值

返回值1代表该位为1,0代表该位为0,-1代表错误。

⑧使用示例

int main(){
    sigset_t block, oldBlock;
    //将1 - 31号信号全部阻塞
    for(int i = 1; i <= 31; i++){
        sigaddset(&block, i);
    }
    int n = sigprocmask(SIG_BLOCK, &block, &oldBlock);
    assert(n == 0);
    //循环打印当前进程的pending位图
    while(true){
        sleep(1);
        sigset_t set;
        sigpending(&set);//获取pending位图
        //循环判断1 - 31位是0还是1并打印
        for(int i = 1; i <= 32; i++){
            if(sigismember(&set, i)) cout << "1";
            else cout << "0";
        }
        cout << endl;
    }

    return 0;
}

Software is like sex: it's better when it's free——Linus Torvalds


如有错误,敬请斧正

猜你喜欢

转载自blog.csdn.net/weixin_61857742/article/details/128602140
今日推荐