signal(2)

信号的总结

Posted by faxiang1230 on November 23, 2018

信号(2)

有什么办法控制另一个进程呢?

在linux系统中每个进程都有自己的虚拟地址空间,所以进程间是相互隔离的。

那么有什么办法来控制一个程序呢,从现在的角度来看,可以使用各种进程间通信,但是通信是双方的事,假如 采用套接字通信,那么确保每个程序都是可控的,需要每个程序都使用套接字来接收消息,难道我只是想写个 helloworld还需要创建个套接字?

所以这件事交给每个程序来实现是会被锤死的,很显然UNIX提供了一套内嵌的机制:信号,来提供控制接口, 通常我们可以使用Ctrl+c来停掉一个进程,kill pid来杀掉一个进程,内核停掉进程的方法也通常是 发送信号让它进入退出流程。

信号

信号是软件中断,提供了一种异步机制来控制程序:通过Ctrl+c来产生SIGINT投递到程序,默认会停止程序。

信号处理可以分为:发送->投递->处理几个过程,这几个过程也会产生非常多有意思的现象。

发送信号可以通过kill/alarm/raise等发送个进程级别,也可以通过pthread_kill/tgkill来发给单独的线程(多线程的mask有好多坑)

投递是内核的事,主要就是标记目标进程/线程的signal记录位。之后每次从内核返回用户态的时候都会检查signal是否被标记,然后选择是否返回给用户空间处理:

1.两个特殊的信号`SIGKILL,SIGSTOP`不能被捕捉,忽略,阻塞,只会在内核态执行默认动作
2.信号被阻塞,不会继续上报
3.信号被捕捉,设置成了忽略/默认,就不需要回用户空间处理了,就地决定
4.信号被捕捉,设置了handler,返回用户空间处理

终于来到了自己注册的信号处理

信号本身是不可靠的,不能保证到达时间和是否能到达,例如程序处于不可中断睡眠状态,这时候是不会被信号唤醒。

信号是不会排队的:当有多个信号按照顺序(SIGA,SIGB,SIGC)发送给进程A,进程A接收到信号的顺序不会严格按照发送顺序处理信号的

信号可以捕捉并且注册信号处理函数(signal,signalaction),处理动作可以为SIG_IGN/SIG_DFL, 也可以为自己的handler.但是只能使用一些可重入函数,就是操作的东西不能和全局状态相关,不然下次 再次进来的时候全局状态改变就会得到不一样的结果。

信号处理函数默认是累加在用户栈上,但是当用户栈比较深时,恰巧你是最后一个倒霉蛋,那么栈溢出被杀了。所以更加安装的办法是使用signalstack来专门为信号处理分配栈,注册信号时标明运行在自己的栈上SA_ONSTACK.

信号的阻塞处理:当正在信号处理时来了新的信号怎么办,信号处理是不可嵌套的,这时候就需要阻塞信号, 等退出当前信号处理时解除信号阻塞,再次从系统调用返回时就能看到被阻塞的信号。

信号中断了系统调用: 处于TASK_INTTERRUPTIABLE中的系统调用被信号唤醒了,并且错误码被置为EINTR,所以在错误处理中EINTR需要特别对待,出错了不能简单认为是问题,而是需要更加深入细致的检查错误码。

信号的使用

进程间通信`

信号是进程间通信方式之一,只能使用自定义的信号USR1,USR2,传输的内容比较简单。
我们通常使用的信号都是不可靠的,没有保证一定能到达对端.

多线程信号处理

进程中线程间共享信号处理函数,每个线程都有自己信号屏蔽集。
我们很可能使用多线程模型来完成复杂的工作,所以在多线程处理信号特别需要注意信号的处理
主线程的信号屏蔽集将会被其他线程继承,在线程中可以单独使用pthread_mask来设置自己的信号屏蔽集。
发送给多线程的进程信号,会投递到没有阻塞该信号的所有线程,通常很多都是终止进程,所以需要处理屏蔽信号。
可以给特定的线程发送信号,但是线程编号的概念是不一样的,我们使用的pthread_create之后gettid()才是真正的线程id。

关机处理SIGTERM

完整的程序运行周期应该有初始化-运行-终止退出几个阶段,通常我们见到的小例子都是没有退出的,直接 就被傻吊了。真正实际运行的应该有终止退出例程的,将正在运行的信息持久化保存,下一次运行载入这次的 信息。在关机的时候会向所有程序发SIGTERM信号,这时候就可以进入关机处理了。

崩溃处理

崩溃处理也是在发生各种错误时,由硬件捕捉到错误之后发现无法修复,内核发送信号给对应的进程,信号没有 捕捉,默认处理终止了进程。通常我们比较关心的内存访问错误会通过SIGSEGV来杀死进程,可以捕捉它,记录堆栈信息。 比较成熟的案例是android debuggerd,就是在linker内塞进了对于各种信号的捕捉才能在进程异常的时候捕捉堆栈信息。

Reference

man 7 signal
UNIX环境高级编程-信号