zoukankan      html  css  js  c++  java
  • 信号 signal sigaction补充

    目前linux中的signal()是通过sigation()函数实现的。

    由signal()安装的实时信号支持排队,同样不会丢失。

    先看signal 和 sigaction 的区别:

    关键是

     struct sigaction act;  

    里面有三个部分,除了 signal函数会关注的 sa_handler 之外,

    还有 sa_mask,这里面可以提供阻塞功能(类似于sigprocmask)

    1. sigemptyset(&act.sa_mask);  
    2. sigaddset(&act.sa_mask, SIGQUIT);  

    类似于:

    sigset_t blockset;     
         sigemptyset(&blockset);     
         sigaddset(&blockset,SIGINT);     
         sigaddset(&blockset,SIGTSTP);     

    意思是在sigaction处理过程中,阻塞这些信号。

    千万注意,开始我也理解错了,是阻塞不是屏蔽也不是忽略,在函数之后还是要处理的。

    这样能够防止处理函数被打断。

    被信号打断的函数会返回错误,errno是EINTR,如果不想手动处理,可以看下面这个sa_flags.

    还有一个 sa_flags,如果 |= SA_RESTART 就能够自动重启被这个信号打断的函数。

    sigaction调用的时候 sigaction(SIGINT, &act, 0);  

    第三个参数是 struct sigaction *oact,表示获得返回的原来的sigaction

    信号内部实现:

    下面这一篇对于信号的内部实现机制,讲的不错:

    http://www.cnblogs.com/blueyunchao0618/p/5953862.html

    当然,我之前的文章也讲的不错。可以看看。

    信号的本质是软件层次上对中断的一种模拟(软中断)。它是一种异步通信的处理机制,事实上,进程并不知道信号何时到来。

    2.信号来源

    (1)程序错误,如非法访问内存

    (2)外部信号,如按下了CTRL+C

    (3)通过kill或sigqueue向另外一个进程发送信号

    1. 信号的生命周期

    信号产生->信号注册->信号在进程中注销->信号处理函数执行完毕

    (2)信号注册

    指的是在目标进程中注册,该目标进程中有未决信号的信息:

    struct sigpending pending:
    struct sigpending{
    struct sigqueue *head, **tail;
    sigset_t signal;
    };

    struct sigqueue{
    struct sigqueue *next;
    siginfo_t info;
    }

    注:也有地方写的是 *tail,未深究。

    其中 sigqueue结构组成的链称之为未决信号链,sigset_t称之为未决信号集。

    信号注册的过程就是将信号值加入到未决信号集siginfo_t中,将信号所携带的信息加入到未决信号链的某一个sigqueue中去。

    对于可靠的信号,可能存在多个未决信号的sigqueue结构,对于每次信号到来都会注册。而不可靠信号只注册一次,只有一个sigqueue结构。

    (3)信号在目标进程中注销

     在进程的执行过程中,每次从系统调用或中断返回用户空间的时候,都会检查是否有信号没有被处理。如果这些信号没有被阻塞,那么就调用相应的信号处理函数来处理这些信号。

    则调用信号处理函数之前,进程会把信号在未决信号链中的sigqueue结构卸掉。是否从未决信号集中把信号删除掉,对于实时信号与非实时信号是不相同的。

    非实时信号:由于非实时信号在未决信号链中只有一个sigqueue结构,因此将它删除的同时将信号从未决信号集中删除。

    实时信号:由于实时信号在未决信号链中可能有多个sigqueue结构,如果只有一个,也将信号从未决信号集中删除掉。如果有多个那么不从未决信号集中删除信号,注销完毕。

    (3)处理过程:

    程序运行在用户态时->进程由于系统调用或中断进入内核->转向用户态执行信号处理函数->信号处理函数完毕后进入内核->返回用户态继续执行程序

    :要多几次内核态切换。原因下面有写

    首先程序执行在用户态,在进程陷入内核并从内核返回的前夕,会去检查有没有信号没有被处理,如果有且没有被阻塞就会调用相应的信号处理程序去处理。首先,内核在用户栈上创建一个层,该层中将返回地址设置成信号处理函数的地址,这样,从内核返回用户态时,就会执行这个信号处理函数。当信号处理函数执行完,会再次进入内核,主要是检测有没有信号没有处理,以及恢复原先程序中断执行点恢复内核栈等工作,这样,当从内核返回后便返回到原先程序执行的地方了。

    注:上面也说明了,内核态下是可以访问用户栈的。

  • 相关阅读:
    sqlhelper使用指南
    大三学长带我学习JAVA。作业1. 第1讲.Java.SE入门、JDK的下载与安装、第一个Java程序、Java程序的编译与执行 大三学长带我学习JAVA。作业1.
    pku1201 Intervals
    hdu 1364 king
    pku 3268 Silver Cow Party
    pku 3169 Layout
    hdu 2680 Choose the best route
    hdu 2983
    pku 1716 Integer Intervals
    pku 2387 Til the Cows Come Home
  • 原文地址:https://www.cnblogs.com/charlesblc/p/6506064.html
Copyright © 2011-2022 走看看