2013-10-07 58 views
0

我在寫一個處理Linux信號的程序。更具體地說,我想在子進程中重新安裝signal SIGINT,但發現它不起作用。SIGINT信號在linux中重新安裝

這裏是我的代碼簡化版本:

void handler(int sig){ 
    //do something 
    exit(0); 
} 

void handler2(int sig){ 
    //do something 
    exit(0); 
} 
int main(){ 

    signal(SIGINT, handler); 

    if ((pid = fork()) == 0) { 
     signal(SIGINT, handler2); // re-install signal SIGINT 

     // do something that takes some time 
     printf("In child process:\n"); 
     execve("foo", argv, environ); // foo is a executable in local dir 

     exit(0); 
    }else{ 
     int status; 
     waitpid(pid, &status, 0); // block itself waiting for child procee to exit 
    } 

    return 0; 
} 

當外殼是印刷「在孩子的過程:」我按CTRL + C。我發現函數handler執行沒有問題,但從未執行handler2

你能幫我解決這個錯誤嗎?

更新: 我希望子進程在foo運行過程中接收到SIGINT信號,這可能嗎?

+1

在您調用execve()之後,子進程不再有任何信號設置,它們都被重置爲SIG_DFL - default。你在問什麼? –

+0

@jimmcnamara我不知道信號設置已被重置爲默認值。謝謝! –

回答

1

這不是一個錯誤 - 調用execve取代了正在運行的二進制映像。程序存儲器中的函數handler2()(以及二進制文件的任何其他函數)不再映射到已被「foo」圖像替換的程序存儲器中,因此所有信號設置都被替換爲默認值。

如果希望信號處理程序在「foo」運行期間處於活動狀態,則必須: a。確保處理函數映射到foo b的內存中。信號處理程序在「foo」啓動後註冊。

一種方法是創建一個共享庫,其中包含信號處理程序和一個定義爲構造函數的init函數,該構造函數註冊所述信號處理程序並通過操作其下的環境強制它進入「foo」你execve foo(環境變量)包含LD_PRELOAD =/path/to/shared_library.so

+0

「共享庫」解決方案對我來說似乎很複雜。你能否對你的建議更具體一些?「如果你希望信號處理程序在」foo「運行期間處於活動狀態,......」? –

+0

execve用程序「foo」替換你的程序。如果你希望你的代碼(信號處理器)在信號發送到foo時運行,你需要使它加載你的代碼。這就是共享庫所做的 – gby

0

@ gby's anwser給出了全面的背景知識。我在這裏提供另一個沒有共享庫的解決方案。

每次子進程停止或終止,父進程都會收到SIGCHLD。你可以處理這個SIGCHLD信號來知道子進程是否被SIGINT終止。在您的處理程序中:

pid_t pid = waitpid(pid_t pid,int * status,int options) 

您可以通過waitpid函數獲取子進程的狀態。

if(WIFSIGNALED(status) && (pid == child_pid)){ 
    if(WTERMSIG(status) == SIGINT){ 
     // now you know your foo has received SIGINT. 
     // do whatever you like. 
    } 
}