在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

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

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

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

            CPU architecture:ARM920T

            本文引用地址:http://www.biyoush.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);//設(shè)置信號位圖
            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);//為進程設(shè)置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()首先為進程設(shè)置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)閉