2009-06-21 26 views
3

我寫我正在開發一個Linux發行版系統關鍵程序。它需要在接收到某些信號時重新啓動,以儘量避免崩潰。問題是,重新啓動後,我無法重新啓用該信號。也就是說,信號不能被接收兩次。在execv()自己完成之後,當新進程調用signal()來設置信號時,SIG_DFL被返回。每次。即使我連續兩次調用它 - 表明它從來沒有設置在第一位。是否有一些奇怪的國旗從原始過程中遺留下來?信號不正確跨越execv重新啓用()

回答

8

您正在下降的事實,你基本上是試圖遞歸處理的信號犯規。

當使用signal()註冊信號處理程序時,該信號編號被阻塞,直到信號處理程序返回 - 實際上,在調用信號處理程序時,內核/ libc塊會發出信號,並在信號處理程序返回後解除阻塞。因爲你永遠不會從信號處理程序返回(而不是你execl一個新的二進制),SIGUSR1保持阻塞,所以不會被第二次捕獲。

這可以通過之前,你發送的第一SIGUSR1後檢查/proc/</pid>/status可以看出。

前:

$ cat /proc/<pid>/status | grep -E "Sig(Cgt|Blk)" 
SigBlk: 0000000000000000 
SigCgt: 0000000000000200 

後:

$ cat /proc/<pid>/status | grep -E "Sig(Cgt|Blk)" 
SigBlk: 0000000000000200 
SigCgt: 0000000000000200 

注意SigCgt指示信號10​​註冊(號碼是位字段;第10位,這相當於SIGUSR1,看到man signal(7)爲號碼)。 SigBlk之前,你的進程,但它發送包含SIGUSR1信號後發送SIGUSR是空的。

你有兩種方法可以解決這個問題:

a)。在sighandler調用execl之前,手動解鎖SIGUSR

sigset_t sigs; 
sigprocmask(0, 0, &sigs); 
sigdelset(&sigs, SIGUSR1); 
sigprocmask(SIG_SETMASK, &sigs); 

B)。使用sigactionSA_NODEFER標誌,而不是signal註冊信號處理程序。這將防止SIGUSR1被擋住了信號處理函數中:

struct sigaction act; 
act.sa_handler = signalhandler; 
act.sa_mask = 0; 
act.sa_flags = SA_NODEFER; 
sigaction(SIGUSR1, &act, 0); 
1

信號處理不跨越exec因爲exec將覆蓋整個地址空間繼承,而不是重置任何信號處理程序將被指向了錯誤的地方。它不是重置的唯一情況是,如果它被設置爲,比方說,SIG_IGN,這是不依賴於預exec進程的地址空間。

+0

這就是我想。我所說的是,在執行完成後,新進程不能再次設置信號 - 而不是繼續執行。無論我做什麼,在從信號處理程序執行完一個進程之後,我都不能再設置相同的信號。 – c4757p 2009-06-21 14:32:45

+0

你有一些我可以測試的代碼嗎?我現在對此很好奇。 – 2009-06-21 14:40:30