by cszhao1980
signal更确切的称呼应该是soft interruption,顾名思义,就是一种能够通过软件手段达到
类似interruption目的的方法。
Unix最多支持NSIG(20)种软中断,进程的u中有u.signal[NSIG]数组,记录每种软中
断的处理方法。
u_signal〔n〕的值 |
当#n中断发生时 |
0 |
此进程将终止自身 |
奇数,非0 |
忽略此软件中断 |
偶数,非0 |
该值为用户空间中一过程的起始地址,应立即执行该过程 |
第#4 8系统调用ssig(),其主要功能就是设置数组“u_signal”,这个sys call有两个参数:
(1)a:signal type(0 ~ NSIG)
(2)u_signal(a)应该被设置的值
3614: ssig()
3615: {
3616: register a;
3617:
3618: a = u.u_arg[0];
3619: if(a<=0 || a>=NSIG || a ==SIGKIL) {
3620: u.u_error = EINVAL;
3621: return;
3622: }
3623: u.u_ar0[R0] = u.u_signal[a]; /返回old值
3624: u.u_signal[a] = u.u_arg[1];
3625: if(u.u_procp->p_sig == a) /clear以前的signal
3626: u.u_procp->p_sig = 0;
3627: }
从代码可知,SIGKIL的处理是不可更改的——而其被初始化为0,即一旦收到此
信号,进程就会终止。
而进程的proc结构中的“psig”项,记录进程目前收到的signal,将其值设置为某一
中断类型编号(亦即在1至NSIG-1之间的一个值),就是对该进程造成一个软中断。
psignal(p, sig)就是用来向进程发送signal的函数,它有两个参数:
参数1:p——执行进程的进程表项
参数2:sig——向该进程发送何种signal
3963: psignal(p, sig)
3964: int *p;
3965: {
3966: register *rp;
3967:
3968: if(sig >= NSIG)
3969: return;
3970: rp = p;
3971: if(rp->p_sig != SIGKIL)
3972: rp->p_sig = sig;
3973: if(rp->p_stat > PUSER) /莱昂指出,这里的“p_stat”应为“p_prio”
3974: rp->p_stat = PUSER; / …
3975: if(rp->p_stat == SWAIT)
3976: setrun(rp);
3977: }
从程序可知:
(1) 一般情况下,连续向进程发送多个signal时,后者会覆盖前者;
(2) SIGKIL例外,一旦发送KILL信号,就不能被覆盖;
(3) 处于SWAIT状态的进程,会被信号叫醒。
要想理解莱昂对3975行的注释,需要翻回到sleep(2066)——当以正的priority
调用sleep时,会将进程状态设置为“SWAIT”,意思为可被信号唤醒(也可理解
为等待信号,即非内核事件)。
相关的程序还有
(1)3949: signal(tp, sig)
为每个p_ttyp == tp(即终端==tp)的进程发送sig信号;
(2)sys call kill
有两个参数:
(1) 由r0传进来,为process id;
(2) 跟在trap指令后(会存放在u_arg[0]中),为signal的type。
其作用是向指定进程发送指定信号。
需要注意的是:
(1) 不能向当前进程(本进程)发信号;
(2) 当输入的process id为0时,表示要向具有同一控制终端(p_ttyp)的
所有进程(不包括#0、#1进程)发信号;
(3) 会进行权限检查——当前进程要末为超级用户(u_uid==0),要末与被
发信号的进程的u_uid相同。之所以仅有此函数进行权限检查,是因为此
函数为unix开放给用户的系统调用,而其他几个函数都是内核态“内部”
函数,故无需进行权限的检查。
博客地址:http://blog.csdn.net/cszhao1980
博客专栏地址:http://blog.csdn.net/column/details/lions-unix.html