2016-02-16
可再入函数
进程捕捉到信号并继续执行时,它首先执行该信号处理程序中的指令。如果从信号处理程序返回,则继续执行在捕捉到信号时进程正在执行的正常指令序列。但在信号处理程序中,不能判断捕捉到的信号时进程执行到何处。
函数不可再入的原因有可能是:
- 已知他们使用静态数据结构
- 它们调用malloc或free
- 它们是标准io函数,标准io库的很多实现都以不可再入的方式使用全局数据结构
因为每个进程只有一个errno,因此作为一个通用的规则,当在信号处理程序中调用可再入函数时,应当在其前保存,在其后恢复errno。在信号处理程序中调用一个不可再入函数,其结果是不可预见的。
可靠信号
当造成信号的事件发生时,为进程产生一个信号。事件可以是硬件异常,软件条件(闹钟时间超过)终端产生的信号或者调用kill函数。在产生信号时,内核通常在进程表中设置某种形式的标志。当对信号做了这种动作时,我们说向一个进程递送了一个信号。在信号产生和递送之间的时间间隔称信号未决(pending)
进程可以选用“信号递送阻塞”。如果为进程产生了一个选择为阻塞的信号,而且对该信号的动作时系统默认动作或者捕捉该信号,则为该进程将此信号保持为未决状态,直到该进程对此信号解除了阻塞或者将此信号的动作更改为忽略。当递送一个原来被阻塞的信号给进程时,而不是在产生该信号时,内核才决定对他的处理方式。于是进程在信号递送给它之前仍可改变对它的动作。进程调用sigpending函数将制定的信号设置为阻塞和未决。
如果在晋城解除对某信号的阻塞之前,这种信号发生了多次,则POSIX.1中使得这些信号排队。但是大多数unix并不对信号排队。unix内核只递送这种信号一次。
如果有多个信号要递送给一个进程,POSIX建议与进程当前状态有关的信号在其他信号之前递送。
每个进程都有一个信号屏蔽字,它规定了当前要阻塞递送到该进程的信号集。对于每种可能的信号,该屏蔽字中都由一位与之对应。对于某种信号,若其对应位置已设置,则当它当前是被阻塞的。进程可以调用sigprocmask来检测和更改当前信号屏蔽字。
信号数可能会超过一个整型数所包含的二进制位数,因此POSIX定义了一个新数据类型sigset_t它保持一个信号集。
kill和raise函数
kill函数将信号发送给进程或者进程组。raise函数则允许进程向自身发送信号。
#include<sys/types.h>
#include<signal.h>
int kill(pid_t pid, int signo)
int raise(int signo)
kill函数中,如果pid>0将信号发送给进程id为pid的进程
pid==0时将信号发送给其进程组id等于发送进程的进程组id,而且发送进程有许可权向其发送信号的所有进程。
pid<0将信号发送给其进程组id等于pid绝对值,而且发送进程有许可权向其发送信号的所有进程。
pid==-1未定义
上面曾提及,进程将信号发送给其他进程需要许可权。超级用户可以将信号发送给另外一个进程。非超级用户,其基本规则是发送者的实际或者有效用户id必须等于接受者的实际或有效用户id。