linux内核中的信号机制--信号发送
CPU architecture:ARM920T
Author:ce123(http://blog.csdn.net/ce123)
应用程序发送信号时,主要通过kill进行。注意:不要被“kill”迷惑,它并不是发送SIGKILL信号专用函数。这个函数主要通过系统调用sys_kill()进入内核,它接收两个参数:
第一个参数为目标进程id,kill()可以向进程(或进程组),线程(轻权线程)发送信号,因此pid有以下几种情况:
- pid>0:目标进程(可能是轻权进程)由pid指定。
- pid=0:信号被发送到当前进程组中的每一个进程。
- pid=-1:信号被发送到任何一个进程,init进程(PID=1)和以及当前进程无法发送信号的进程除外。
- pid<-1:信号被发送到目标进程组,其id由参数中的pid的绝对值指定。
由于sys_kill处理的情况比较多,分析起来比较复杂,我们从tkill()函数入手,这个函数把信号发送到由参数指定pid指定的线程(轻权进程)中。tkill的内核入口是sys_tkill(kernel/signal.c),其定义如下:
[plain]view plaincopyprint?
- /*
- *Sendasignaltoonlyonetask,evenifitsaCLONE_THREADtask.
- */
- asmlinkagelong
- sys_tkill(intpid,intsig)
- {
- structsiginfoinfo;
- interror;
- structtask_struct*p;
- /*Thisisonlyvalidforsingletasks*/
- if(pid<=0)//对参数pid进行检查
- return-EINVAL;
- info.si_signo=sig;//根据参数初始化一个siginfo结构
- info.si_errno=0;
- info.si_code=SI_TKILL;
- info.si_pid=current->tgid;
- info.si_uid=current->uid;
- read_lock(&tasklist_lock);
- p=find_task_by_pid(pid);//获取由pid指定的线程的task_struct结构
- error=-ESRCH;
- if(p){
- error=check_kill_permission(sig,&info,p);//权限检查
- /*
- *Thenullsignalisapermissionsandprocessexistence
- *probe.Nosignalisactuallydelivered.
- */
- if(!error&&sig&&p->sighand){
- spin_lock_irq(&p->sighand->siglock);
- handle_stop_signal(sig,p);
- //对某些特殊信号进程处理,例如当收到SIGSTOP时,需要把信号队列中的SIGCONT全部删除
- error=specific_send_sig_info(sig,&info,p);//把信号加入到信号队列
- spin_unlock_irq(&p->sighand->siglock);
- }
- }
- read_unlock(&tasklist_lock);
- returnerror;
- }
sys_tkill函数主要是通过pecific_send_sig_info()函数实现的,下面我们看一下pecific_send_sig_info()(kernel/signal.c)的定义:
[plain]view plaincopyprint?
- staticint
- specific_send_sig_info(intsig,structsiginfo*info,structtask_struct*t)
- {
- intret=0;
- if(!irqs_disabled())
- BUG();
- assert_spin_locked(&t->sighand->siglock);
- if(((unsignedlong)info>2)&&(info->si_code==SI_TIMER))
- /*
- *Setupareturntoindicatethatwedroppedthesignal.
- */
- ret=info->si_sys_private;
- /*信号被忽略*/
- /*Short-circuitignoredsignals.*/
- if(sig_ignored(t,sig))
- gotoout;
- /*Supportqueueingexactlyonenon-rtsignal,sothatwe
- cangetmoredetailedinformationaboutthecauseof
- thesignal.*/
- if(LEGACY_QUEUE(&t->pending,sig))
- gotoout;
- ret=send_signal(sig,info,t,&t->pending);//实际的发送工作
- if(!ret&&!sigismember(&t->blocked,sig))
- signal_wake_up(t,sig==SIGKILL);
- out:
- returnret;
- }
这里注意到想send_signal()传递的参数时t->pending,也就是连接Private Signal Queue的那条链。最后,如果发送成功就调用signal_wake_up()来唤醒目标进程,这样可以保证该进程进入就绪状态,从而有机会被调度执行信号处理函数。
现在我们来看看send_signal()(kernel/signal.c)函数,这个函数的主要工作就是分配并初始化一个sigqueue结构,然后把它添加到信号队列中。
[plain]view plaincopyprint?
- staticintsend_signal(intsig,structsiginfo*info,structtask_struct*t,
- structsigpending*signals)
- {
- structsigqueue*q=NULL;
- intret=0;
- /*
- *fast-pathedsignalsforkernel-internalthingslikeSIGSTOP
- *orSIGKILL.
- */
- if((unsignedlong)info==2)
- gotoout_set;
- /*Real-timesignalsmustbequeuedifsentbysigqueue,or
- someotherreal-timemechanism.Itisimplementation
- definedwhetherkill()doesso.Weattempttodoso,on
- theprincipleofleastsurprise,butsincekillisnot
- allowedtofailwithEA
linux内核信号机制信号发 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)