2012-10-01 29 views
6

我在C編寫了一個基本的shell,而且我正在努力暫停一個子進程。在用SIGTSTP暫停子進程之後,shell沒有響應

我認爲我的信號處理程序是正確的,並且我的子進程正在暫停,但是在此之後,終端應該返回到父進程並且沒有發生。

孩子被暫停,但我的外殼沒有註冊任何輸入或輸出了。 tcsetpgrp()似乎沒有幫助。

這裏是我的信號處理程序在我的shell代碼爲SIGTSTP:

void suspend(int sig) { 
    pid_t pid; 
    sigset_t mask; 
    //mpid is the pgid of this shell. 
    tcsetpgrp(STDIN_FILENO, mpid); 
    tcsetpgrp(STDOUT_FILENO, mpid); 
    sigemptyset(&mask); 
    sigaddset(&mask, SIGTSTP); 
    sigprocmask(SIG_UNBLOCK, &mask, NULL); 
    signal(SIGTSTP, SIG_DFL); 
    //active.pid is the pid of the child currently in the fg. 
    if (active.pid != 0) { 
     kill(active.pid, SIGTSTP); 
    } 
    else{ 
     //if this code is being run in the child, child calls SIGTSTP on itself. 
     pid = getpid(); 
     if (pid != 0 && pid != mpid){ 
      kill(pid, SIGTSTP); 
     } 
    } 
    signal(SIGTSTP, suspend); 
} 

誰能告訴我,我做錯了什麼?

我是否將我的shell與孩子一起掛起,我是否需要以某種方式將stdin和stdout返回給shell?我將如何做到這一點?

謝謝!

回答

0

tcsetpgrp是指定什麼是前臺工作。當你的shell在前臺產生一個作業(沒有&)時,它應該創建一個新的進程組,並且使前臺作業(控制終端的作業,而不是STDIN上的任何作業)成爲前臺作業。然後,按下CTRL-Z,該作業將獲得TSTP。這是終端暫停工作,而不是你的外殼。您的外殼不應該陷入TSTP或將TSTP發送給任何人。

它應該只是wait()它已經產生了,當它已經停止檢測(和索回前景組和內部懸掛標記作業)的工作。你fg命令將使作業的再次PGID前臺進程組和發送SIGCONT給它,並再次等待它,而bg將只發送SIGCONT

+1

感謝您的回覆。我嘗試了你說的話,但是當我拿走我的信號處理程序時,終端會暫停父母並返回bash。我需要父母繼續跑步。 – user1710304

+1

這顯然是錯誤的,沒有捕獲SIGTSTP肯定會導致他的shell暫停,並且會讓子進程繼續。 他需要抓住它,所以他的外殼不會中止。 我現在面臨着同樣的問題,他現在面臨早些時候 – Fingolfin

+1

@AdelQodmani,當您按Ctrl-Z時,只有終端的前臺進程組收到SIGTSTP。正在等待其啓動進程終止的shell是在一個進程組中,該進程組不是終端的前臺進程組。如果你喜歡,你可以_IGNORE_ SIGTSTP,這可能是大多數shell所做的。我的觀點是你需要使用終端的前臺進程組。 –

2

這是一個老問題,但我仍然認爲我找到了答案。
不是你寫你的父母的代碼,但我猜想它看起來像:

int main(){ 
    pid_t pid = fork(); 
    if(pid == 0){ //child process 
     //call some program 
    else //parent process 
     wait(&status); //or waitpid(pid, &status, 0) 
     //continue with the program 
} 

的問題是等待()或waitpid函數(),它的外觀,如果你運行在OS的程序一樣像Ubuntu後使用Ctrl + Z您的子進程正在獲取SIGTSTP,但父進程中的wait()函數仍在等待!

這樣做的正確方法是用pause()替換父節點中的wait(),並創建另一個捕獲SIGCHLD的處理程序。例如:

void sigHandler(int signum){ 
    switch(signum){ 
     case SIGCHLD: 
      // note that the last argument is important for the wait to work 
      waitpid(-1, &status, WNOHANG); 
      break; 
    } 
} 

在子進程後,這種情況得到按Ctrl +ž父進程也收到SIGCHLD和暫停()的返回。

0

我可能遲到在這裏回答這個問題,但是當我被同樣的問題困住時,這是有效的。根據手冊頁tcsetpgrp()

函數tcsetpgrp()使得該方法組與處理組ID PGRP關聯到FD上的終端上的前臺進程組, 其必須的控制終端呼叫過程,並且 仍然與其會話相關聯。此外,pgrp必須是屬於與調用 進程相同的會話的 (非空)進程組。

如果tcsetpgrp()由後臺進程組的成員在 其會話調用,調用進程不會阻止或忽略 SIGTTOU,一個SIGTTOU信號被髮送到這樣的背景 過程組的所有成員。

因此,在我創建可以到達前臺的進程之前,在我的shell程序中忽略了信號SIGTTOU。如果我不忽略這個信號,那麼內核將把這個信號發送到我的shell程序並掛起它。