打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
理解信号(进程篇)
作者:新浪微博(@NP等不等于P

计算机学习微信公众号(jsj_xx)

信号就是软件中断,和硬件中断有很多类似之处。本文分享我们对信号这种异步事件处理的理解,仅考虑进程,不涉及多线程(如有错误,还请指正,谢谢)。

【参考linux kernel source code 4.0,syscall rt_sigaction()、send_signal()、do_signal()

1 不可靠信号

由于信号历史悠久,我们还得从不可靠信号讲起。

不可靠的根因在于存在竞态时间窗口,毕竟异步就难以预测发生信号的时机。早期信号的问题有:

  • 每个信号仅期望触发一次。触发完内核立即将信号处理函数重置为默认值,这样自定义处理必须手动恢复,从而在自定义信号处理里、但是在恢复这个动作前,会有一个竞态窗口。

  • 有时阻止不了信号。由于缺少信号掩码操作,导致在pause()前可能发生信号,由于这个竞态窗口的存在从而导致pause可能再也等不到信号。

对于pause问题,setjmp是一个治标不治本的解决方案。因为它的暴力跳转会让其它的信号处理夭折,并且还不能解决好信号掩码的在迁移时的保护和恢复。

可见,这些竞态窗口的存在,就是早期信号不可靠的根因。可靠信号的一个目的,就是要消灭掉这些竞态窗口。

2 可靠信号

我们(计算机学习微信公众号:jsj_xx)的理解是:sigprocmask/sigpending/sigsetjmp/siglongjmp/sigsuspend,这些函数存在的意义就是要解决上文中提到的竞态窗口问题的!

我们逐个分析:

  • 对于sigprocmask和sigpending,质朴的(原始的)解决方式。

    最细粒度地解决竞态窗口。

  • sigsuspend相当于sigprocmask和pause的合成,提供设置信号掩码后等待的一个原子操作。

    一个基于sigprocmask的具体应用(扩展)。一个原子的智能化(手动设置自定义掩码和自动恢复老掩码)操作。不能提供sigprocmask和其它慢速系统调用的合成,很遗憾。

  • siglongsetjmp和siglongjmp,则是setjmp和longjmp的信号版本,提供跳转时的信号掩码现场的保护和恢复。

    然而,跳转方式依旧是一个指标不治本的方案。

可见,对于等待一个全局变量(全局变量在一个信号处理中设置)这样一个处理,总算有了完美方案:sigsuspend。结合sigaction函数,我们是这么理解的:

  • sigprocmask在信号处理外部实施指定的屏蔽(掩码)操作。

  • sigaction函数在信号处理内部实施指定的屏蔽(同一信号不可重入)操作。

这样,内外结合,自然拥有完全的可靠性。

3 兼容方案

基于sigaction函数,其中也支持对早期不可靠信号的支持:

  • SA_NODEFER

    让信号采用早期的不自动屏蔽的行为。

  • SA_RESETHAND

    让信号采用早期的自动重置默认处理的行为。

  • SA_RESTART

    此信号要让系统调用重启(当然也需要系统调用的支持,像read/write/wait等慢速系统调用都是支持重启的)。

  • SA_INTERRUPT

    此信号不要让系统调用重启。

可见,调用sigaction时指定SA_RESETHAND(参考代码,同SA_ONESHOT)和SA_NODEFER(参考代码,同SA_NOMASK)就可以完美实现早期的信号方式了。关于重启系统调用,注意SIGALRM的处理:一定不能设置为SA_RESTART方式,或者更苛刻(安全)的,需要设置为SA_INTERRUPT方式。

4 信号可重入

早期的信号处理中重置默认处理的行为,可以看作是在变通解决重入问题(当然,现在已经通过自动掩码使得同一信号处理不可重入了)。信号处理里要保证调用异步信号安全的函数。这是显然的,毕竟信号是异步处理。需要注意的是,多线程里即使信号处理中使用异步信号安全的函数,也还是需要保存和恢复errno的。

异步信号不安全函数的原因有:

  • 使用静态数据结构

  • 使用glibc malloc/free函数

  • 使用标准io函数(比如printf)

信号处理中是不能使用这些不安全的函数的,否则后果很严重。触类旁通,想想fork()之后、exec()之前,子进程在这段时间里,就只能调用异步信号安全函数,这是一个道理的。

5 针对同一信号处理时再次发生的计数

传统信号(编号从1到31)是不计次数的,只计是否发生过。实时信号(编号从32到64)是记录次数的,当然是有上限的(通过ulimit查看)。

需要注意,计数区别不能成为评判信号可不可靠的标准,想想硬件中断的处理就明白了。

6 总结

可靠信号要解决的问题,无非是(早期信号的)异步处理伴随的竞态窗口问题,可以说是通过sigprocmask和sigaction联合解决了。最后要说的是,信号本质就是软件中断,因为确实形神兼备硬件中断。。。

新浪微博(@NP等不等于P

计算机学习微信公众号(jsj_xx)

原创技术文章,感悟计算机,透彻理解计算机!

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
操作系统实验 信号操作函数 siginttest.c
signal函数
Linux信号与信号处理
从kernel原始码的角度分析signal的错误用法和注意事项(zt)
linux信号 linux signal
Linux信号处理机制(三)——信号捕捉
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服