发射信号
Linux下,一个进程给其他进程发送信号的API是kill函数。其定义如下:
#include<sys/types.h>#include<signal.h>int kill(pid_t pid,int sig);
该函数把信号sig发送给目标进程;目标进程由pid参数指定,其可能的取值及含义如下:
pid参数 | 含义 |
---|---|
pid>0 | 信号发送给PID为pid的进程 |
pid=0 | 信号发送给本进程组内的其他进程 |
pid=-1 | 信号发送给除init进程外的所有进程,但发送者需要拥有对目标进程发送信号的权限 |
pid<-1 |
信号发送给组ID为-pid的进程组中的所有成员 |
Linux定义的信号值都大于0,如果sig取值为0,则kill函数不发送任何信号。但将sig设置为0可以用来检测目标进程或进程组是否存在,因为检查工作总是在信号发送之前就执行。不过这种检测方式是不可靠的。一方面由于进程PID的回绕,可能导致被检测的PID不是我们期望的进程的PID;另一方面,这种检测方法不是原子操作。
该函数成功时返回0,失败则返回-1并设置errno。几种可能的errno如下:
errno | 含义 |
---|---|
EINVAL | 无效的信号 |
EPERM | 该进程没有权限发送信号给任何一个目标进程 |
ESRCH | 目标进程或进程组不存在 |
信号处理方式
目标进程在收到信号时,需要定义一个接收函数来处理之。信号处理函数的原型如下:
#include<signal.h>typedef void(*__sighandler_t)(int);
信号处理函数只带有一个整型参数,该参数用来指示信号类型。信号处理函数应该是可重入的,否则很容易引发一些竞态条件。所以在信号处理函数中严禁调用一些不安全的函数。
除了用户自定义信号处理函数外,bits/signum.h头文件中还定义了信号的两种其他处理方式——SIG_IGN和SIG_DEL:
#include<bits/signum.h>#define SIG_DFL((__sighandler_t)0)#define SIG_IGN((__sighandler_t)1)
SIG_IGN表示忽略目标信号,SIG_DFL表示使用信号的默认处理方式。信号的默认处理方式有如下几种:结束进程(Term)、忽略信号(Ign)、结束进程并生成核心转储文件(Core)、暂停进程(Stop),以及继续进程(Cont)。
Linux信号
Linux的可用信号都定义在bits/signum.h头文件中,其中包括标准信号和POSIX实时信号。
这里只讨论标准信号,如下图
我们并不需要在代码中处理所有这些信号。本章后面将重点介绍与网络编程关系紧密的几个信号:SIGHUP、SIGPIPE和SIGURG。后面还将介绍SIGALRM、SIGCHLD等信号的使用。
中断系统调用
如果程序在执行处于阻塞状态的系统调用时接收到信号,并且我们为该信号设置了信号处理函数,则默认情况下系统调用将被中断,并且errno被设置为EINTR。我们可以使用sigaction函数(见后文)为信号设置SA_RESTART标志以自动重启被该信号中断的系统调用。
对于默认行为是暂停进程的信号(比如SIGSTOP、SIGTTIN),如果我们没有为它们设置信号处理函数,则它们也可以中断某些系统调用(比如connect、epoll_wait)。POSIX没有规定这种行为,这是Linux独有的。
信号函数
signal系统调用
要为一个信号设置处理函数,可以使用下面的signal系统调用:
#include<signal.h>_sighandler_t signal(int sig,_sighandler_t _handler)
sig参数指出要捕获的信号类型。_handler参数是_sighandler_t类型的函数指针,用于指定信号sig的处理函数。
signal函数成功时返回一个函数指针,该函数指针的类型也是_sighandler_t。这个返回值是前一次调用signal函数时传入的函数指针,或者是信号sig对应的默认处理函数指针SIG_DEF(如果是第一次调用signal的话)。
signal系统调用出错时返回SIG_ERR,并设置errno。
sigaction系统调用
设置信号处理函数的更健壮的接口是如下的系统调用:
#include<signal.h>int sigaction(int sig,const struct sigaction*act,struct sigaction*oact);
sig参数指出要捕获的信号类型,act参数指定新的信号处理方式,oact参数则输出信号先前的处理方式(如果不为NULL的话)。
act和oact都是sigaction结构体类型的指针,sigaction结构体描述了信号处理
的细节,其定义如下:
struct sigaction{#ifdef__USE_POSIX199309union{_sighandler_t sa_handler;void(*sa_sigaction)(int,siginfo_t*,void*);}_sigaction_handler;#define sa_handler__sigaction_handler.sa_handler#define sa_sigaction__sigaction_handler.sa_sigaction#else_sighandler_t sa_handler;#endif_sigset_t sa_mask;int sa_flags;void(*sa_restorer)(void);};