linux信号理解

一、信号的基本概念     
     当在shell下启动一个前台的进程时,用户可以通过键盘上ctrl+c使这个进程结束,即产生了一个硬件中断。当cpu在执行这个进程的代码时,该进程的用户空间代码暂停执行,cpu从用户态切换到内核态处理硬件中断。终端驱动程序将键盘上输入的ctrl+c解释成一个 SIGINT信号,  记录在进程的PCB中。当某个时刻要从内核返回该进程的用户空间代码继续执行之前,需要首先处理PCB中记录的信号。发现有SIGINT信号待处理,这个信号默认处理动作是终止进程,所以直接终止进程而不在返回它的用户空间代码执行。
1.信号的产生方式
  • 1.键盘。用户在终端按下某些键时,终端驱动程序会发送信号给前台进程(注意是前台进程,后台进程不能用键盘发送信号)。
  • 2.操作系统或者编译器检查到异常并通知内核,内核向当前进程发送适当信号
  • 3.一些命令或函数。当进程调用kill函数可发送信号给另一个进程。alarm函数超时也会产生SIGALRM信号,abort函数使当前进程收到SIGABRT信号而终止。

2.信号的处理动作
  • 1.忽略信号
  • 2.执行该信号默认处理动作
  • 3.提供一个信号处理函数,要求内核在处理该函数时切换到用户态执行这个处理函数,即信号捕捉
二、阻塞信号
1.基本概念
     实际执行信号的处理动作称为 信号递达,信号从产生到递达之间的状态称为 信号未决, 进程可以选择阻塞某个信号,被阻塞的信号产生时将保持在未决状态,知直到进程解除对信号的阻塞才执行递达的动作。
     *阻塞和忽略是不同的,阻塞不会递达,而忽略是在递达后的一种处理动作。
      每个信号都有两个标志位分别表示阻塞(block)和未决(pending),还有一个函数指针表示处理动作。信号产生时,内核在进程控制块中设置该信号的未决标志,知道信号递达时才清除该标志位。    
信号在内核中的示意图

 其中block表中1表示阻塞,0表示未阻塞,pending表中1表示产生信号,0表示未产生信号
图中:SIGHUP信号未阻塞也未产生,当递达时执行默认处理动作
          SIGINT信号产生了,但是被阻塞,所以暂时不能递达,它的处理动作是SIG_IGN表示忽略。但在没解除阻塞之前,不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。
          SIGQUIT信号未产生过,一旦产生则被阻塞,处理动作是用户自定义函数sighandler
    
       *若在进程解除对某型号阻塞之前这个信号产生多次将如何处理?
      常规信号在递达之前产生多以只记录一次,pending表只有一个bit表示未决标志。
2.信号集操作函数
     信号集不是信号量集。信号集是在用户空间描述信号,信号集可以表示pending表,又可称为pending信号集,用0、1表示,但是不允许使用位操作操作,系统提供对应的接口操作信号集,pending信号集和pending表对应。block表表示信号屏蔽字,也是信号集(block信号集)。
     sigset_t类型对于每种信号用一个bit表示有效或无效的状态。以前是一些函数,可以调用他们来操作sigset_t变量。(注意这些信号量集的每个bit不能用位操作符改变)

 注意:在使用sigset_t类型变量之前一定要调用sigemptyset或sigfillset做初始化使信号处于确定的状态。

sigprocmask函数
     sigprocmask函数读取或更改信号屏蔽字(阻塞信号集),成功返回0,出错返回-1

 如果oset是⾮非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是⾮非空指 针,则 更改进程的信号屏蔽字,参数how指⽰示如何更改。如果oset和set都是⾮非空指针,则先 将原来的信号 屏蔽字备份到oset⾥里,然后根据set和how参数更改信号屏蔽字。假设当前的 信号屏蔽字为mask,下表说明了how参数的可选值。
      若调用sigprocmask解除了对当前若干个未决信号的阻塞,则在函数返回前,至少将其中一个信号递达
how参数:

igpending函数
     sigpending函数读取当前进程的未决信号集,通过set参数传出,调用成功返回0,出错返回-1

例:sigpending读取当前进程的未决信号集,通过set参数传出。调⽤用成功则返回0,出错则返回 -1

运行:

三、捕捉信号
    1.相关概念
     如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。

对于一个用户自定义的信号处理函数,处理过程如下(以上图SIGQUT信号为例):

  • 1.用户程序注册了SIGQUIT信号处理函数sighandler
  • 2.当前正在执行main函数,此时发生中断或异常切换到内核态
  • 3.中断处理完毕后返回用户态main函数之前需检查信号,发现有SIGQUIT信号递达
  • 4.内核决定返回用户态后不是恢复main函数上下文继续执行而是执行sighandler函数,sighandler和main函数使用不同的堆栈空间,它们之间不存在调用和被调用关系,是两个独立的控制流程
  • 5.sighandler函数返回后自动执行特殊的系统调用sigreturn再次进入内核态
  • 6.若没有新的信号要递达,这次再返回用户态就是恢复main函数的上下文继续执行
2.相关函数
  • sigaction函数
     sigaction函数可以读取和修改与指定信号相关联的处理动作,调用成功返回0,出错返回-1.
     对于参数signum是指定信号的编号,若act指定非空,则根据act写该该信号的处理动作。若oldact非空,则通过其传出该信号原来的处理动作

其中sigaction的结构体为

 sa_handler赋值为SIG_IGN传给sigaction表示忽略此信号。赋值为SIG_DEL表示执行系统默认动作,赋值为一个函数指针表示用自定义函数捕捉信号,这个自定义处理函数返回值为void,可以带一个int参数,通过参数可以知道当前信号的编号,这样就可以用同一个函数处理多信号。(这个函数也是一个回调函数,是被系统所调用)
     当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,当信号处理函数返回时自动恢复原来的信号屏蔽字,保证了处理某个信号时,若这种信号再次产生,则阻塞到房钱处理结束为止
  • pause函数

 pause函数使调用进程挂起直到有信号递达。若信号的处理动作是终止进程,则进程终止,pause函数没机会返回;若信号的处理动作是忽略,则继续挂起,pause函数不返回;若信号的处理动作是捕捉,则调用了信号处理函数之后pause返回-1,error设置为EINTR,pause函数只有出错的返回值,错误码EINTR表示信号被中断。
sleep()函数的实现

  • 1、main函数调⽤用mysleep函数,后者调⽤用sigaction注册了SIGALRM信号的处理函数  sig_alrm。 
  • 2. 调⽤用alarm(nsecs)设定闹钟。         
  • 3. 调⽤用pause等待,内核切换到别的进程运⾏行。         
  • 4. nsecs秒之后,闹钟超时,内核发SIGALRM给这个进程。   
  • 5. 从内核态返回这个进程的⽤用户态之前处理未决信号,发现有SIGALRM信号,其处理函数是sig_alrm。 
  • 6. 切换到⽤用户态执⾏行sig_alrm函数,进⼊入sig_alrm函数时SIGALRM信号被⾃自动屏蔽, 从sig_alrm函数返回时SIGALRM信号⾃自动解除屏蔽。然后⾃自动执⾏行系统调⽤用 sigreturn再次进⼊入 内核,再返回⽤用户态继续执⾏行进程的主控制流程(main函数调⽤用 的mysleep函数)。 
  • 7. pause函数返回-1,然后调⽤用alarm(0)取消闹钟,调⽤用sigaction恢复SIGALRM信号以前的处理 动作

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值