Linux信号机制

Linux信号机制

信号机制是进程间相互传递消息的一种方法,信号全称为软中断信号,信号是进程控制的一部分。从进程的描述符PCB中,也可以看到进程关于信号处理的身影。

/*
    35. 信号处理 
        1) signal: 指向进程的信号描述符
        2) sighand: 指向进程的信号处理程序描述符
    */
    struct signal_struct *signal;
    struct sighand_struct *sighand;
    /*
        3) blocked: 表示被阻塞信号的掩码
        4) real_blocked: 表示临时掩码
    */
    sigset_t blocked, real_blocked;
    sigset_t saved_sigmask;     
    /*
        5) pending: 存放私有挂起信号的数据结构
    */
    struct sigpending pending;
    /*
        6) sas_ss_sp: 信号处理程序备用堆栈的地址
        7) sas_ss_size: 表示堆栈的大小
    */
    unsigned long sas_ss_sp;
    size_t sas_ss_size;
    /*
        8) notifier
        设备驱动程序常用notifier指向的函数来阻塞进程的某些信号
        9) otifier_data
        指的是notifier所指向的函数可能使用的数据。
        10) otifier_mask
        标识这些信号的位掩码
    */
    int (*notifier)(void *priv);
    void *notifier_data;
    sigset_t *notifier_mask;

进程之间可以通过系统调用相互发送信号;内核也可以因为某种事件向用户进程发送某种信号,通知进程发生了某种事件,但是请注意,信号只是用来通知进程发生了事件,其本身不会携带任何信息。

可以从如下几个方面来理解信号:1、进程如何存储信号。2、进程如何感知信号。3、进程如何处理信号。

1.进程如何存储信号

在进程描述符中有一个未决(pending)信号集合(所谓的未决是指信号产生,但还未对信号做出处理决定),信号的注册其实就是指在这个未决(pending)信号集中标记对应的信号数值二进制位为1.

上面代码列出了进程中关于信号处理的所有字段

    /*
        5) pending: 存放私有挂起信号的数据结构
    */
    struct sigpending pending;

struct sigpending pending;就是用来做信号标记的,给一个进程发送的所有信号都存储在这个结构体中,那么它是如何标记的呢,我们可以对这个结构体进行展开。

struct sigpending {
        struct list_head list;
        sigset_t signal;
};
/* A `sigset_t' has a bit for each signal.  */
# define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
  {
    unsigned long int __val[_SIGSET_NWORDS];
  } __sigset_t;

pending结构体包含2个字段struct list_headsigset_t,其中sigset_t这个结构体只有一个数组成员,在32位环境下,这个数组大小为32;在64位环境下,这个数组大小为16。个人理解这个数组大小标记了进程可以同时接收的最大信号数目。不管是32位环境还是64位环境,均只能最大容纳16个信号(32位环境下,需要两个数组元素表示64个不同的信号)。

现在我们就可以理解,当某一个进程发送一个信号给当前进程时,操作系统就会将该进程对应的pending集合中表示相应信号的位图的二进制位中0改为1。位图只是用来标记有没有待处理的信号。

信号的分类

Linux操作系统有64中不同的信号,分为非可靠信号(1-32)和可靠信号(33-64)。二者的区别主要体现在注册方面。

非可靠信号

试图对一个进程发送一个非可靠信号时,若发现位图上对应的位为0,则置为1;若发现位图上对应的位已经为1,则直接返回。简单地说就是若信号还未注册,则注册一下,若已经注册,则什么都不做

可靠信号注册

当试图对一个进程发送一个可靠信号时,若发现位图上对应的位为0,则置为1,若发现位图上对应的位已经为1,对该位不进行操作但依旧在链表里加入一个待处理节点。也就是说,每次对进程发送一个可靠信号时,不管该进程之前是否收到过相同的信号,总是会在list_head链表里加入待处理节点

未完待续。。。。

原文地址:https://www.cnblogs.com/wangdongfang/p/13800457.html