linux訊號機制

來源:互聯網
上載者:User
linux訊號機制
 
 
訊號提供了一種通知進程系統事件發生的機制,它也是作為使用者進程之間通訊和同步的
一種原始機制。在進程遷移的情況下,如何處理訊號呢?這部分介紹了MOSIX系統對訊號
機制的處理。
LINUX訊號機制

訊號是非同步進程間通訊機制,是在軟體層次上對中斷機制的一種類比。LINUX核心的信
號機制符合POSIX.4的規定,這是POSIX.1標準的一個超集。

每個進程的task_struct結構中都有個指標sig,指向一個singal_struct結構,結構中的
數組action[]相當於一個訊號向量表,每個元素確定了進程接收到一個具體的訊號時應
該採取的行動。

struct signal_struct {
    atomic_t        count;
    struct k_sigaction  action[_NSIG];
    spinlock_t      siglock;
};

那麼系統如何判斷一個進程是否有訊號在等待處理呢?這是通過task_struct結構中的si
gpending成員。task_struct結構中的blocked成員則為屏蔽訊號的集合,pending成員則
為訊號隊列,每產生一個訊號則把它掛入這個隊列,訊號位元影像signal也儲存在其中。

使用者常常要自己定義對訊號的處理常式,並且使用者的處理函數是位於使用者空間的。LINUX
提供了系統調用signal(sys_signal)和sigaction(sys_sigaction 或sys_rt_sigacti
on)為訊號設定處理向量。使用者佈建訊號處理的時機我們是不能確定的,可以在進程遷
移前,也可以在進程遷移之後,進程可以在不同的節點間多次遷移,因此,如何保證信
號不被丟失並且都能被正確處理就很重要。並且我們注意到,進程在遷移時,並不將信
號向量表遷移到目標進程,而只是將進程的非同步訊號和強制訊號資訊傳送到目標進程【
參見mig_send_misc()和mig_do_receive_misc()】。

struct asig_h
{
    unsigned int sigs;/*訊號*/
    int nforced;/*核心發送的強制訊號的個數*/
};
struct mosix_task
{。。。。。。。
uint32_t asig;      /*到達REMOTE的訊號 */
siginfo_t *forced_sigs; /* REMOTE強制訊號資訊*/
int nforced_sigs;   /* REMOTE強制訊號的個數 */
short sigmig;       /* 遷移時接收的訊號 */
}

int  mig_send_misc(int credit)
{ struct mig_misc_h m;
register struct task_struct *p = current;
………………..
m.asig.sigs = p->mosix.asig;
m.asig.nforced = p->mosix.nforced_sigs;
forced_sigs = p->mosix.forced_sigs;
sti();
if(comm_send(MIG_MISC, &m, sizeof(m), forced_sigs,
                    m.asig.nforced * sizeof(siginfo_t), 0))
        ………………
}

因此,我們可以說進程訊號處理的狀態是保留在DEPUTY方的。這樣做也是很自然的。首
先在MOSIX中,對於REMOTE進程,幾乎所有的系統調用都是請求DEPUTY來處理,和訊號相
關的一些系統調用也不了例外。例如,sigprocmask()改變本進程得訊號屏蔽位元影像,sigp
ending()檢查有哪些訊號已到達而未被處理,signal()和sigaction()安裝訊號處
理程式。其次,在不少核心操作中,進程進入睡眠以後剛被喚醒時,都會活動訊號的存
在從而提前返回到使用者空間。而DEPUTTY和REMOTE可以分別看作對系統上下文和使用者上下
文的抽象,所以DEPUTY保留著訊號處理的狀態。

訊號響應

對訊號的檢測和響應總是發生在系統空間,通常發生在兩種情況下:第一,當前進程由
於系統調用、中斷或異常而進入系統空間以後,從系統空間返回到使用者空間的前夕。第
二,當前進程在核心中進入睡眠以後剛被喚醒時,由於訊號的存在而提前返回到使用者空
間。

當進程由於中斷進入系統空間以後,中斷處理常式服務完後,將會轉到入口ret_from_in
tr 。當進程由於異常而進入系統空間後,將會跳到error_code從而最終轉到ret_from_e
xception處理【參見entry.S】。如果中斷或異常發生於使用者空間,則轉移到ret_check_
reschedule,否則發生於核心空間,則到達restore_all。當進程由於系統調用進入系統
空間,將最終走到ret_from_sys_call。

ENTRY(ret_from_sys_call)
。。。。。
ret_check_reschedule:
        cli                       # need_resched and signals atomic test
        cmpl $0,need_resched(%ebx)/*判斷是否需要調度*/
        jne reschedule
        cmpl $0,sigpending(%ebx)  /*判斷是否有懸掛的訊號/
        jne signal_return        /*如果有訊號待處理,則跳到signal_return */
  straight_to_mosix:
        call SYMBOL_NAME(mosix_pre_usermode_actions)
        testl %eax,%eax
        jne ret_from_sys_call
restore_all:
        RESTORE_ALL
  ALIGN
signal_return:
        sti                             # 開中斷
handler
        testl $(VM_MASK),EFLAGS(%esp)/*是否處於VM86模式*/
        movl %esp,%eax
        jne v86_signal_return  /*是VM86模式的話,則轉到v86_signal_return */
call SYMBOL_NAME(do_signal) /* do_signal 對訊號進行處理*/
        jmp straight_to_mosix

從代碼中我們可以看到,如果有訊號待處理,則在退出系統空間前,會跳到signal_retu
rn,調用do_signal處理訊號。

我們看看do_signal ,它對訊號作出具體的反應。如果當前進程是REMOTE,它只是簡單
的返回0。否則,該函數根據當前進程的signal域,確定進程收到了那些訊號。對進程收
到的每一個訊號,從進程的訊號等待隊列中找到該訊號對應的附加資訊,從進程的sig域
的action數組中找到訊號的處理常式及其相關的資訊。於是,如果使用者佈建了訊號處理
程式(在使用者空間中),則最終會通過函數handle_signal()準備好對處理常式的執行

使用者提供的訊號處理常式是在使用者空間執行的,而且執行完畢以後還還要回到系統空間
。LINUX實現的機制如下:

使用者空間堆棧中為訊號處理常式的執行預先建立一個架構,架構中包括一個作為局部量
的資料結構,並把系統空間的"原始架構"儲存在這個資料結構中
在訊號處理常式中插入對系統調用sigreturn()的調用
將系統空間堆棧中"原始架構"修改成為執行訊號處理常式所需的架構
"返回"到使用者空間,但是卻執行訊號處理常式
訊號處理常式執行完畢後,通過系統調用sigreturn()重返系統空間
在系統調用sigreturn()中從使用者空間恢複"原始架構"
最後再返回到使用者空間,繼續執行原先的使用者程式

對於本地進程,這是在handle_signal()中由setup_rt_frame()或setup_frame()作出安
排的。但是,對於DEPUTY進程,則是通過mosix_deputy_setup_frame()實現的。因為,
我們已經知道,DEPUTY是永遠運行在核心態中的;進程遷移後,程式碼片段和資料區段等都完
全遷移到遠程REMOTE進程。因此,訊號處理常式必然是在REMOTE進程上啟動並執行。那麼,
這又是如何?的呢。

mosix_deputy_setup_frame()通過deputy_request()函數向REMOTE發送DEP_SETUPFRAM
E請求,REMOTE將在remote_wait()函數中接收到該請求,調用remote_setup_frame()
來響應該請求。REMOTE進程在remote_setup_frame()中,根據DEPUTY傳來的參數,通
過setup_rt_frame()或setup_frame()安排好一個架構。

這樣,當REMOTE進程從系統空間返回到使用者空間時,將執行訊號處理常式。然後,將通
過sigreturn()系統調用重返系統空間。sys_sigreturn()的作用就是從使用者空間執行信
號處理常式的架構中恢複當初系統空間中的原始架構。它通過restore_sigcontext()
恢複架構的。但是對於DEPUTY進程,則是通過mosix_deputy_restore_sigcontext()函
數來恢複系統空間的原始架構的【參見sys_sigreturn()】。這裡,因為是REMOTE進程調
用sigreturn()系統調用,因此根據我們前面對系統調用的分析,REMOTE進程向DEPUTY進
程發送REM_SYSCALL請求,DEPUTY將在通過deputy_syscall()函數中調用sys_sigretur
n()來響應該請求。

mosix_deputy_restore_sigcontext()則向REMOTE進程發送DEP_RESTORESIGCONTEXT請
求。REMOTE在向DEPUTY發送REM_SYSCALL請求後,將處於remote_wait()迴圈中等待REM_S
YSCALL請求的應答【參見remote_standard_system_call()】。REMOTE在remote_wait()
中接收到DEP_RESTORESIGCONTEXT請求後,則通過remote_restore_sigcontext()函數調
用restore_sigcontext()真正恢複核心空間的原始架構。此後,當REMOTE進程從系統
空間返回後,將回到訊號處理前原先的使用者空間處繼續往下執行。

訊號發送

發送一個訊號給進程可以在使用者空間通過系統調用發送,如通過sys_kill和
syr_rt_sigqueueinfo調用發送。核心也可以通過force_sig()和force_sig_info()向進
程強制發送訊號,將屏蔽位強制清除,不允許目標進程忽略該訊號。

在使用者空間向一個進程發送訊號由系統調用sys_kill()實現。該函數調用函數kill_some
thing_info(),它根據情況,或者向單個進程發送訊號(kill_proc_info()),或者向一
個進程組中的所有進程發送訊號(kill_pg_info()), 最終都會調用函數send_sig_info(
)來完成真正的訊號發送。kill_pg_info()中,通過for_each_local_task(p)來尋找屬於
同組的進程。這是因為MOSIX中, 訊號只會發給本地進程,而不會發送給REMOTE進程的
。對於REMOTE進程,當通過kill()發送訊號時,根據我們前面對系統調用的分析,我
們知道最終將是由DEPUTY來調用sys_kill()。因此,訊號是被掛入DEPUTY的task_struct
結構中的pending隊列裡。

非同步和強制訊號的處理

核心也會向進程發送訊號,例如當頁面異常而又無法恢複時,do_page_fault()頁面異
常處理常式會通過force_sig()zx向當前進程發送一個SIGBUS訊號。核心發送的訊號一般
都是需要立即作出反應的。MOSIX對系統發送訊號的處理方式也和使用者發送訊號有所不同
,核心發送的"強制"訊號都儲存在mosix_task的forced_sigs指標中。

我們首先看看函數force_sig_info()。如果訊號的目的地為REMOTE進程,則:

如果處於中斷服務中,則系統panic
得到進程已有的強制訊號數(n= t->mosix.nforced_sigs)並試圖分配記憶體(x =
kmalloc((n + 1) * sizeof(siginfo_t), GFP_KERNEL))用於儲存這n+1個訊號資訊
如果記憶體配置失敗,則盡量再次發送該訊號send_sig(sig, t, 0);返回0
因為分配記憶體返回時,可能已經處理了一部分訊號,因此要進行檢測。如果是,則釋放
剛剛申請的記憶體,跳到第二步
將儲存的siginfo_t和新的info拷貝到分配的記憶體中,儲存在mosix結構的forced_sigs中
,並增加強制訊號計數t->mosix.forced_sigs = x; t->mosix.nforced_sigs++;

我們前面已經分析過,REMOTE進程從系統空間返回到使用者態之前,將會調用remote_pre_
usermode_actions()函數。remote_pre_usermode_actions()函數將會檢測當前進程是否
有非同步或"強制"訊號待處理。如果有,它會通過函數transfer_signals_to_deputy()
發送REM_ASIG請求將訊號傳遞給DEPUTY處理【參見remote_pre_usermode_actions()】。
DEPUTY則會通過函數deputy_analyse_remote_signals()來處理REM_ASIG請求。它首先
從串連中獲得"強制"訊號資訊,通過force_sig_info()向當前進程(即DEPUTY本身)
發送強制資訊。然後得到每個訊號,依次處理,一般都是通過send_sig發給當前進程。

轉自:http://blog.chinaunix.net/u/14053/showart_82160.html

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.