<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > linux內(nèi)核中的信號機制--信號發(fā)送

          linux內(nèi)核中的信號機制--信號發(fā)送

          作者: 時間:2016-11-22 來源:網(wǎng)絡 收藏
          Kernel version:2.6.14

          CPU architecture:ARM920T

          本文引用地址:http://www.ex-cimer.com/article/201611/320005.htm

          Author:ce123(http://blog.csdn.net/ce123)

          應用程序發(fā)送信號時,主要通過kill進行。注意:不要被“kill”迷惑,它并不是發(fā)送SIGKILL信號專用函數(shù)。這個函數(shù)主要通過系統(tǒng)調(diào)用sys_kill()進入內(nèi)核,它接收兩個參數(shù):

          第一個參數(shù)為目標進程id,kill()可以向進程(或進程組),線程(輕權(quán)線程)發(fā)送信號,因此pid有以下幾種情況:

          • pid>0:目標進程(可能是輕權(quán)進程)由pid指定。
          • pid=0:信號被發(fā)送到當前進程組中的每一個進程。
          • pid=-1:信號被發(fā)送到任何一個進程,init進程(PID=1)和以及當前進程無法發(fā)送信號的進程除外。
          • pid<-1:信號被發(fā)送到目標進程組,其id由參數(shù)中的pid的絕對值指定。
          第二個參數(shù)為需要發(fā)送的信號。

          由于sys_kill處理的情況比較多,分析起來比較復雜,我們從tkill()函數(shù)入手,這個函數(shù)把信號發(fā)送到由參數(shù)指定pid指定的線程(輕權(quán)進程)中。tkill的內(nèi)核入口是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)//對參數(shù)pid進行檢查
          12. return-EINVAL;
          13. info.si_signo=sig;//根據(jù)參數(shù)初始化一個siginfo結(jié)構(gòu)
          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結(jié)構(gòu)
          20. error=-ESRCH;
          21. if(p){
          22. error=check_kill_permission(sig,&info,p);//權(quán)限檢查
          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函數(shù)主要是通過pecific_send_sig_info()函數(shù)實現(xiàn)的,下面我們看一下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);//實際的發(fā)送工作
          23. if(!ret&&!sigismember(&t->blocked,sig))
          24. signal_wake_up(t,sig==SIGKILL);
          25. out:
          26. returnret;
          27. }
          首先調(diào)用sig_ignored檢查信號是否被忽略,然后檢查發(fā)送的信號是不是普通信號,如果是普通信號,就需要根據(jù)信號位圖來檢查當前信號隊列中是否已經(jīng)存在該信號,如果已經(jīng)存在,對于普通信號不需要做任何處理。然后調(diào)用send_signal來完成實際的發(fā)送工作,send_signal()是信號發(fā)送的重點,除sys_tkill之外的函數(shù),最終都是通過send_signal()來完成信號的發(fā)送工作的。

          這里注意到想send_signal()傳遞的參數(shù)時t->pending,也就是連接Private Signal Queue的那條鏈。最后,如果發(fā)送成功就調(diào)用signal_wake_up()來喚醒目標進程,這樣可以保證該進程進入就緒狀態(tài),從而有機會被調(diào)度執(zhí)行信號處理函數(shù)。

          現(xiàn)在我們來看看send_signal()(kernel/signal.c)函數(shù),這個函數(shù)的主要工作就是分配并初始化一個sigqueue結(jié)構(gòu),然后把它添加到信號隊列中。

          [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結(jié)構(gòu)
          22. if(q){//如果成功分配到sigqueue結(jié)構(gòu),就把它添加到隊列中,并對其初始化
          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結(jié)構(gòu)
          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. }
          從上面的分析可以看出,我們看到信號被添加到信號隊列之后,會調(diào)用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標志,說明該進程有延遲的信號要等待處理。然后再調(diào)用wake_up_state()喚醒目標進程,如果目標進程在其他的CPU上運行,wake_up_state()將返回0,此時調(diào)用kick_process()向該CPU發(fā)送一個處理器間中斷。當中斷返回前戲,會為當前進程處理延遲的信號。

          此后當該進程被調(diào)度時,在進程返回用戶空間前,會調(diào)用do_notify_resume()處理該進程的信號。



          評論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();