您的位置 首页 电路

linux内核中的信号机制–信号发送

Kernelversion:2614CPUarchitecture:ARM920TAuthor:ce123(http:blogcsdnnetce123)应用程序发送信号时,主要通过kill进行。注

Kernel version:2.6.14

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 plaincopy

print?

  1. /*
  2. *Sendasignaltoonlyonetask,evenifitsaCLONE_THREADtask.
  3. */
  4. asmlinkagelong
  5. sys_tkill(intpid,intsig)
  6. {
  7. structsiginfoinfo;
  8. interror;
  9. structtask_struct*p;
  10. /*Thisisonlyvalidforsingletasks*/
  11. if(pid<=0)//对参数pid进行查看
  12. return-EINVAL;
  13. info.si_signo=sig;//依据参数初始化一个siginfo结构
  14. info.si_errno=0;
  15. info.si_code=SI_TKILL;
  16. info.si_pid=current->tgid;
  17. info.si_uid=current->uid;
  18. read_lock(&tasklist_lock);
  19. p=find_task_by_pid(pid);//获取由pid指定的线程的task_struct结构
  20. error=-ESRCH;
  21. if(p){
  22. error=check_kill_permission(sig,&info,p);//权限查看
  23. /*
  24. *Thenullsignalisapermissionsandprocessexistence
  25. *probe.Nosignalisactuallydelivered.
  26. */
  27. if(!error&&sig&&p->sighand){
  28. spin_lock_irq(&p->sighand->siglock);
  29. handle_stop_signal(sig,p);
  30. //对某些特别信号进程处理,例如当收到SIGSTOP时,需求把信号行列中的SIGCONT悉数删去
  31. error=specific_send_sig_info(sig,&info,p);//把信号加入到信号行列
  32. spin_unlock_irq(&p->sighand->siglock);
  33. }
  34. }
  35. read_unlock(&tasklist_lock);
  36. returnerror;
  37. }

sys_tkill函数首要是经过pecific_send_sig_info()函数完结的,下面咱们看一下pecific_send_sig_info()(kernel/signal.c)的界说:

[plain]view plaincopy

print?

  1. staticint
  2. specific_send_sig_info(intsig,structsiginfo*info,structtask_struct*t)
  3. {
  4. intret=0;
  5. if(!irqs_disabled())
  6. BUG();
  7. assert_spin_locked(&t->sighand->siglock);
  8. if(((unsignedlong)info>2)&&(info->si_code==SI_TIMER))
  9. /*
  10. *Setupareturntoindicatethatwedroppedthesignal.
  11. */
  12. ret=info->si_sys_private;
  13. /*信号被疏忽*/
  14. /*Short-circuitignoredsignals.*/
  15. if(sig_ignored(t,sig))
  16. gotoout;
  17. /*Supportqueueingexactlyonenon-rtsignal,sothatwe
  18. cangetmoredetailedinformationaboutthecauseof
  19. thesignal.*/
  20. if(LEGACY_QUEUE(&t->pending,sig))
  21. gotoout;
  22. ret=send_signal(sig,info,t,&t->pending);//实践的发送作业
  23. if(!ret&&!sigismember(&t->blocked,sig))
  24. signal_wake_up(t,sig==SIGKILL);
  25. out:
  26. returnret;
  27. }

首要调用sig_ignored查看信号是否被疏忽,然后查看发送的信号是不是一般信号,假如是一般信号,就需求依据信号位图来查看当时信号行列中是否现已存在该信号,假如现已存在,关于一般信号不需求做任何处理。然后调用send_signal来完结实践的发送作业,send_signal()是信号发送的要点,除sys_tkill之外的函数,终究都是经过send_signal()来完结信号的发送作业的。

这儿留意到想send_signal()传递的参数时t->pending,也便是衔接Private Signal Queue的那条链。最终,假如发送成功就调用signal_wake_up()来唤醒方针进程,这样能够确保该进程进入安排妥当状况,然后有机会被调度履行信号处理函数。

现在咱们来看看send_signal()(kernel/signal.c)函数,这个函数的首要作业便是分配并初始化一个sigqueue结构,然后把它添加到信号行列中。

[plain]view plaincopy

print?

  1. staticintsend_signal(intsig,structsiginfo*info,structtask_struct*t,
  2. structsigpending*signals)
  3. {
  4. structsigqueue*q=NULL;
  5. intret=0;
  6. /*
  7. *fast-pathedsignalsforkernel-internalthingslikeSIGSTOP
  8. *orSIGKILL.
  9. */
  10. if((unsignedlong)info==2)
  11. gotoout_set;
  12. /*Real-timesignalsmustbequeuedifsentbysigqueue,or
  13. someotherreal-timemechanism.Itisimplementation
  14. definedwhetherkill()doesso.Weattempttodoso,on
  15. theprincipleofleastsurprise,butsincekillisnot
  16. allowedtofailwithEAGAINwhenlowonmemorywejust
  17. makesureatleastonesignalgetsdeliveredanddont
  18. passontheinfostruct.*/
  19. q=__sigqueue_alloc(t,GFP_ATOMIC,(sig
  20. ((unsignedlong)info<2||
  21. info->si_code>=0)));//分配sigqueue结构
  22. if(q){//假如成功分配到sigqueue结构,就把它添加到行列中,并对其初始化
  23. list_add_tail(&q->list,&signals->list);
  24. switch((unsignedlong)info){
  25. case0:
  26. q->info.si_signo=sig;
  27. q->info.si_errno=0;
  28. q->info.si_code=SI_USER;
  29. q->info.si_pid=current->pid;
  30. q->info.si_uid=current->uid;
  31. break;
  32. case1:
  33. q->info.si_signo=sig;
  34. q->info.si_errno=0;
  35. q->info.si_code=SI_KERNEL;
  36. q->info.si_pid=0;
  37. q->info.si_uid=0;
  38. break;
  39. default:
  40. copy_siginfo(&q->info,info);//复制sigqueue结构
  41. break;
  42. }
  43. }else{
  44. if(sig>=SIGRTMIN&&info&&(unsignedlong)info!=1
  45. &&info->si_code!=SI_USER)
  46. /*
  47. *Queueoverflow,abort.Wemayabortifthesignalwasrt
  48. *andsentbyuserusingsomethingotherthankill().
  49. */
  50. return-EAGAIN;
  51. if(((unsignedlong)info>1)&&(info->si_code==SI_TIMER))
  52. /*
  53. *Setupareturntoindicatethatwedropped
  54. *thesignal.
  55. */
  56. ret=info->si_sys_private;
  57. }
  58. out_set:
  59. sigaddset(&signals->signal,sig);//设置信号位图
  60. returnret;
  61. }

从上面的剖析能够看出,咱们看到信号被添加到信号行列之后,会调用signal_wake_up()唤醒这个进程,signal_wake_up()(kernel/signal.c)的界说如下:

[plain]view plaincopy

print?

  1. /*
  2. *Tellaprocessthatithasanewactivesignal..
  3. *
  4. *NOTE!werelyonthepreviousspin_lockto
  5. *lockinterruptsforus!Wecanonlybecalledwith
  6. *”siglock”held,andthelocalinterruptmust
  7. *havebeendisabledwhenthatgotacquired!
  8. *
  9. *Noneedtosetneed_reschedsincesignaleventpassing
  10. *goesthrough->blocked
  11. */
  12. voidsignal_wake_up(structtask_struct*t,intresume)
  13. {
  14. unsignedintmask;
  15. set_tsk_thread_flag(t,TIF_SIGPENDING);//为进程设置TIF_SIGPENDING标志
  16. /*
  17. *ForSIGKILL,wewanttowakeitupinthestopped/tracedcase.
  18. *Wedontcheckt->stateherebecausethereisaracewithit
  19. *executinganotherprocessorandjustnowenteringstoppedstate.
  20. *Byusingwake_up_state,weensuretheprocesswillwakeupand
  21. *handleitsdeathsignal.
  22. */
  23. mask=TASK_INTERRUPTIBLE;
  24. if(resume)
  25. mask|=TASK_STOPPED|TASK_TRACED;
  26. if(!wake_up_state(t,mask))
  27. kick_process(t);
  28. }

signal_wake_up()首要为进程设置TIF_SIGPENDING标志,阐明该进程有推迟的信号要等待处理。然后再调用wake_up_state()唤醒方针进程,假如方针进程在其他的CPU上运转,wake_up_state()将回来0,此刻调用kick_process()向该CPU发送一个处理器间中止。当中止回来前戏,会为当时进程处理推迟的信号。

尔后当该进程被调度时,在进程回来用户空间前,会调用do_notify_resume()处理该进程的信号。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/fangan/dianlu/262417.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部