glibc-raise源码阅读
摘要
本文通过源码分析详细解读了glibc中raise函数的实现及其作用时机,指出raise函数通过调用tgkill发送信号给线程或进程,并触发对应的信号处理函数。作者还对raise在单线程和多线程中的行为进行了对比,强调其多线程安全性及在信号处理中的关键作用。此外,文章结合abort函数和信号处理机制,进一步阐述了raise的使用场景及其在内核态与用户态切换中的处理时机。
问题
关于raise函数,有几个想调查的问题:
raise是怎么实现的?raise的作用时机?
源码
先来看raise的实现, 代码比较简单, 我们也无需递归地去看每一个函数地实现.
raise调用的就是tgkill. tgkill相比kill和tkill, 增加了多线程的保护, 通过tid和tgid基本保证信号传递到正确的线程, 而不会因为线程的消亡和构建而传递到错误的线程.
| |
raise看起来很简单, 我们也可以通过man raise来详细了解一下, 其说明的是:
- raise在单线程中等同于kill;
- raise在多线程中等同于pthread_kill;
- raise在信号处理函数处理结束后返回;
- raise是多线程安全的;
- glibc 2.3.3版本后raise调用的是tgkill.(本文即是tgkill)
所以我们可以解答开头的问题:
raise是怎么实现的?
等同于tgkill, rasie发送信号给线程(进程), 然后调用对应的信号处理函数. 回忆上一篇《glibc-abort源码阅读》, 调用abort的时候就是调用raise发送SIGABRT信号, 会有SIG_DFL之类的处理函数绑定SIGABRT信号, 从而造成进程退出.
raise的作用时机?
同信号处理, 参考《进程控制和通信(四) · PCB介绍》可以知道, raise是在用户陷入内核态再从内核态返回用户态的过程中会被处理. 所以, abort的作用时机也是等同于raise.
