新聞中心

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

        linux內(nèi)核中的信號(hào)機(jī)制--信號(hào)發(fā)送

        作者: 時(shí)間:2016-11-22 來(lái)源:網(wǎng)絡(luò) 收藏
        Kernel version:2.6.14

        CPU architecture:ARM920T

        本文引用地址:http://www.104case.com/article/201611/320005.htm

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

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

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

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

        由于sys_kill處理的情況比較多,分析起來(lái)比較復(fù)雜,我們從tkill()函數(shù)入手,這個(gè)函數(shù)把信號(hào)發(fā)送到由參數(shù)指定pid指定的線(xiàn)程(輕權(quán)進(jì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)//對(duì)參數(shù)pid進(jìn)行檢查
        12. return-EINVAL;
        13. info.si_signo=sig;//根據(jù)參數(shù)初始化一個(gè)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指定的線(xiàn)程的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. //對(duì)某些特殊信號(hào)進(jìn)程處理,例如當(dāng)收到SIGSTOP時(shí),需要把信號(hào)隊(duì)列中的SIGCONT全部刪除
        31. error=specific_send_sig_info(sig,&info,p);//把信號(hào)加入到信號(hào)隊(duì)列
        32. spin_unlock_irq(&p->sighand->siglock);
        33. }
        34. }
        35. read_unlock(&tasklist_lock);
        36. returnerror;
        37. }

        sys_tkill函數(shù)主要是通過(guò)pecific_send_sig_info()函數(shù)實(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. /*信號(hào)被忽略*/
        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);//實(shí)際的發(fā)送工作
        23. if(!ret&&!sigismember(&t->blocked,sig))
        24. signal_wake_up(t,sig==SIGKILL);
        25. out:
        26. returnret;
        27. }
        首先調(diào)用sig_ignored檢查信號(hào)是否被忽略,然后檢查發(fā)送的信號(hào)是不是普通信號(hào),如果是普通信號(hào),就需要根據(jù)信號(hào)位圖來(lái)檢查當(dāng)前信號(hào)隊(duì)列中是否已經(jīng)存在該信號(hào),如果已經(jīng)存在,對(duì)于普通信號(hào)不需要做任何處理。然后調(diào)用send_signal來(lái)完成實(shí)際的發(fā)送工作,send_signal()是信號(hào)發(fā)送的重點(diǎn),除sys_tkill之外的函數(shù),最終都是通過(guò)send_signal()來(lái)完成信號(hào)的發(fā)送工作的。

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

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

        [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),就把它添加到隊(duì)列中,并對(duì)其初始化
        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);//設(shè)置信號(hào)位圖
        60. returnret;
        61. }
        從上面的分析可以看出,我們看到信號(hào)被添加到信號(hào)隊(duì)列之后,會(huì)調(diào)用signal_wake_up()喚醒這個(gè)進(jìn)程,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);//為進(jìn)程設(shè)置TIF_SIGPENDING標(biāo)志
        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()首先為進(jìn)程設(shè)置TIF_SIGPENDING標(biāo)志,說(shuō)明該進(jìn)程有延遲的信號(hào)要等待處理。然后再調(diào)用wake_up_state()喚醒目標(biāo)進(jìn)程,如果目標(biāo)進(jìn)程在其他的CPU上運(yùn)行,wake_up_state()將返回0,此時(shí)調(diào)用kick_process()向該CPU發(fā)送一個(gè)處理器間中斷。當(dāng)中斷返回前戲,會(huì)為當(dāng)前進(jìn)程處理延遲的信號(hào)。

        此后當(dāng)該進(jìn)程被調(diào)度時(shí),在進(jìn)程返回用戶(hù)空間前,會(huì)調(diào)用do_notify_resume()處理該進(jìn)程的信號(hào)。



        評(píng)論


        技術(shù)專(zhuān)區(qū)

        關(guān)閉
        主站蜘蛛池模板: 永善县| 饶河县| 朔州市| 三台县| 桂阳县| 福鼎市| 鸡泽县| 新田县| 小金县| 历史| 长兴县| 金华市| 崇明县| 金川县| 仪陇县| 太和县| 鄂托克旗| 抚宁县| 双峰县| 建昌县| 天水市| 浮梁县| 霞浦县| 黑河市| 潼南县| 报价| 黄大仙区| 洛南县| 石景山区| 万宁市| 保山市| 新和县| 木兰县| 宜丰县| 福鼎市| 安乡县| 南汇区| 宜兴市| 桃江县| 米易县| 抚顺市|