• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-4  評論-40  文章-117  trackbacks-0


            信號與進程是分不開的,而把信號與進程的筆記分開來寫,是因為我覺得這個信號太難搞懂了,特別是APUE信號這一章還把信號結合歷史來介紹弄的我云里霧里。 

            信號本質上是在軟件層次上對中斷機制的一種模擬,他有幾種產生方式和處理方式(APUE有介紹),下面帶著疑惑從幾個角度對信號進行介紹 


            (一)    站在進程的角度

            進程發現和接受信號

            我們知道,信號是異步的,一個進程不可能等待信號的到來,也不知道信號會到來,那么,進程是如何發現和接受信號呢?實際上,信號的接收不是由用戶進程來完成的,而是由內核代理。當一個進程P2向另一個進程P1發送信號后,內核接受到信號,并將其放在P1的信號隊列當中。當P1再次陷入內核態時,會檢查信號隊列,并根據相應的信號調取相應的信號處理函數

            Task _struct 是進程控制塊(PCB),詳見          http://oss.org.cn/kernel-book/ch04/4.3.htm

             

            信號檢測和響應時機

            剛才我們說,當P1再次陷入內核時,會檢查信號隊列。那么,P1什么時候會再次陷入內核呢?陷入內核后在什么時機會檢測信號隊列呢?

            1.      當前進程由于系統調用、中斷或異常而進入系統空間以后,從系統空間返回到用戶空間的前夕。

            2.      當前進程在內核中進入睡眠以后剛被喚醒的時候(必定是在系統調用中),或者由于不可忽略信號的存在而提前返回到用戶空間


            進入信號處理函數

             

             


            對于sigprocmask 會進入內核空間、pause需要從進入睡眠這兩者都符合檢測處理信號函數的條件,所以存在忽略信號的情況,而APUE講sigsuspend的之后真是晦澀難懂,其實他主要做的工作就是等待一個中斷然后執行相應的handle處理

            所以我感覺例子中的

            sigsuspend(&zeromask);

            sigprocmask(SIG_SETMASK, &oldmask,NULL);

            是不是可以直接替換為

            Sigsuspend(&oldmask)

            因為測試情況難以出現,這里只是個人理解并未得到驗證

             

             

            (二)  站在信號自身的角度

             

            信號生命周期:

             對于一個完整的信號生命周期(從信號發送到相應的處理函數執行完畢)來說,可以分為三個重要的階段,這三個階段由四個重要事件來刻畫:

            1.信號誕生;

            2.信號在進程中注冊完畢;

            3.信號在進程中的注銷完畢;

            4.信號處理函數執行完畢。

            相鄰兩個事件的時間間隔構成信號生命周期的一個階段。

             

                詳細描述各個生命周期

            1.     信號"誕生"。

            信號的誕生指的是觸發信號的事件發生(如檢測到硬件異常、定時器超時以及調用信號發送函數kill()或sigqueue()等)。 

            2.      信號在目標進程中"注冊"。

            這里注冊定義不是由signal或者sigaction實現的,而是說信號發生之后內核中自動對信號的注冊保存。

            進程的task_struct結構中有關于本進程中未決信號的數據成員: 

            struct sigpending pending;

            struct sigpending

            {

                struct sigqueue *head, **tail;

                sigset_t signal;

            };

            第一、第二個成員分別指向一個sigqueue類型的結構鏈(稱之為"未決信號信息鏈")的首尾,第三個成員是進程中所有未決信號集,信息鏈中的每個sigqueue結構體刻畫一個特定信號所攜帶的信息,并指向下一個sigqueue結構:

            struct sigqueue

            {

                struct sigqueue *next;

                siginfo_t info;

            };

                信號在進程中注冊指的就是信號值加入到進程的未決信號集中(sigpending結構的第二個成員sigset_t signal),并且信號所攜帶的信息被保留到未決信號信息鏈的某個sigqueue結構中。只要信號在進程的未決信號集中,表明進程已經知道這些信號的存在,但還沒來得及處理,或者該信號被進程阻塞。

            注: 

                當一個實時信號發送給一個進程時,不管該信號是否已經在進程中注冊,都會被再注冊一次,因此,信號不會丟失,因此,實時信號又叫做"可靠信號"。這意味著同一個實時信號可以在同一個進程的未決信號信息鏈中占有多個sigqueue結構(進程每收到一個實時信號,都會為它分配一個結構來登記該信號信息,并把該結構添加在未決信號鏈尾,即所有誕生的實時信號都會在目標進程中注冊);

            當一個非實時信號發送給一個進程時,如果該信號已經在進程中注冊,則該信號將被丟棄,造成信號丟失。因此,非實時信號又叫做"不可靠信號"。這意味著同一個非實時信號在進程的未決信號信息鏈中,至多占有一個sigqueue結構。一個非實時信號誕生后,(1)、如果發現相同的信號已經在目標結構中注冊,則不再注冊,對于進程來說,相當于不知道本次信號發生,信號丟失;(2)、如果進程的未決信號中沒有相同信號,則在進程中注冊自己。在APUE的不可靠信號章節中需要每次重新聲明sinal_hanle函數,這個是說的以前Unix系統的處理,現在可靠不可靠就是上面所說的實時與注冊次數的區別。


            3.信號在進程中的注銷。

            在目標進程執行過程中,會檢測是否有信號等待處理(每次從系統空間返回到用戶空間時都做這樣的檢查)。(“sigprocmask返回前,也至少會將其中一個未決且未阻塞的信號遞送給進程”)如果存在未決信號等待處理且該信號沒有被進程阻塞,則在運行相應的信號處理函數前,進程會把信號在未決信號鏈中占有的結構卸掉。是否將信號從進程未決信號集中刪除對于實時與非實時信號是不同的。對于非實時信號來說,由于在未決信號信息鏈中最多只占用一個sigqueue結構,因此該結構被釋放后,應該把信號在進程未決信號集中刪除(信號注銷完畢);而對于實時信號來說,可能在未決信號信息鏈中占用多個sigqueue結構,因此應該針對占用gqueue結構的數目區別對待:如果只占用一個sigqueue結構(進程只收到該信號一次),則應該把信號在進程的未決信號集中刪除(信號注銷完畢)。否則,不在進程的未決信號集中刪除該信號(信號注銷完畢)。進程在執行信號相應處理函數之前,首先要把信號在進程中注銷。


            4.信號生命終止。

            進程注銷信號后,立即執行相應的信號處理函數,執行完畢后,信號的本次發送對進程的影響徹底結束。 


            注: 

            1)信號注冊與否,與發送信號的函數(如kill()或sigqueue()等)以及信號安裝函數(signal()及sigaction())無關,只與信號值有關(信號值小于SIGRTMIN的信號最多只注冊一次,信號值在SIGRTMIN及SIGRTMAX之間的信號,只要被進程接收到就被注冊)。

            2)在信號被注銷到相應的信號處理函數執行完畢這段時間內,如果進程又收到同一信號多次,則對實時信號來說,每一次都會在進程中注冊;而對于非實時信號來說,無論收到多少次信號,都會視為只收到一個信號,只在進程中注冊一次。

             

            (三)  進程和信號兩者的角度來看

            實際執行信號的處理動作稱為信號遞達(Delivery),信號從產生到遞達之間的狀態,稱為信號未決(Pending)。進程可以選擇阻塞(Block)某個信號。被阻塞的信號產生時將保持在未決狀態,直到進程解除對此信號的阻塞,才執行遞達的動作。注意,阻塞和忽略是不同的,只要信號被阻塞就不會遞達,而忽略是在遞達之后可選的一種處理動作。信號在內核中的表示可以看作是這樣的:

            信號在內核中的表示示意圖

             每個信號都有兩個標志位分別表示阻塞和未決,還有一個函數指針表示處理動作。信號產生時,內核在進程控制塊中設置該信號的未決標志,直到信號遞達才清除該標志。在上圖的例子中,

            1.      SIGHUP信號未阻塞也未產生過,當它遞達時執行默認處理動作。

            2.      SIGINT信號產生過,但正在被阻塞,所以暫時不能遞達。雖然它的處理動作是忽略,但在沒有解除阻塞之前不能忽略這個信號,因為進程仍有機會改變處理動作之后再解除阻塞。

            3.      SIGQUIT信號未產生過,一旦產生SIGQUIT信號將被阻塞,它的處理動作是用戶自定義函數sighandler。

             


            posted on 2012-02-10 17:49 李陽 閱讀(660) 評論(1)  編輯 收藏 引用 所屬分類: Linux

            評論:
            # re: Linux 信號 (轉) 2013-05-19 10:18 | cjg
            好文,清晰。  回復  更多評論
              
            亚洲综合精品香蕉久久网97| 伊人色综合久久| 久久久久国产精品嫩草影院| 久久人妻AV中文字幕| 久久综合久久自在自线精品自| 久久精品水蜜桃av综合天堂 | 久久SE精品一区二区| 97精品依人久久久大香线蕉97| 久久久久亚洲AV成人片| 韩国三级中文字幕hd久久精品| 久久国产一片免费观看| 青草国产精品久久久久久| 精品久久人人做人人爽综合| 亚洲精品高清国产一线久久| 精品人妻伦九区久久AAA片69| 思思久久精品在热线热| 国内精品久久久久伊人av| 国内精品伊人久久久久妇| 成人亚洲欧美久久久久| 久久av无码专区亚洲av桃花岛| 久久免费99精品国产自在现线 | 久久五月精品中文字幕| 99久久久精品免费观看国产| 老男人久久青草av高清| 久久久人妻精品无码一区| 国产精品久久久久久| 国内精品久久久久久久久电影网 | 亚洲国产精品久久久久久| 性色欲网站人妻丰满中文久久不卡| 久久久久国色AV免费看图片| 99久久99久久精品免费看蜜桃| 丁香色欲久久久久久综合网| 久久久久亚洲AV综合波多野结衣 | 久久久久人妻一区二区三区| 久久国产精品视频| 国产成人精品久久| 精品99久久aaa一级毛片| 国产国产成人久久精品| 国产精品xxxx国产喷水亚洲国产精品无码久久一区| 久久精品一本到99热免费| 伊人久久久AV老熟妇色|