2012-10-01 2 views
6

私はCで基本シェルをコーディングしています。私は現在、子プロセスを中断しています。子プロセスをSIGTSTPでサスペンドした後、シェルが応答しない

私のシグナルハンドラは正しいと思いますが、私の子プロセスは中断していますが、その後、ターミナルは親プロセスに戻り、それは起こっていません。

子は中断されていますが、シェルは入力や出力をもう登録していません。 tcsetpgrp()は役に立たないようです。

ここに私のシグナルハンドラは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); 
} 

誰もが私が間違ってやっているものを私に伝えることができますか?

私は子供と一緒にシェルを中断していますが、何とかシェルにstdinとstdoutを返す必要がありますか?どうすればいい?

ありがとうございます!

答えて

0

tcsetpgrpフォアグラウンドジョブを指定することです。あなたのシェルが(&なしで)フォアグラウンドでジョブを生成すると、新しいプロセスグループを作成し、フォアグラウンドジョブ(STDINにあるものではなく、制御端末のもの)にする必要があります。次に、CTRL-Zを押すと、そのジョブはTSTPを取得します。あなたのシェルではなく、仕事を一時停止するターミナルです。あなたのシェルは、TSTPをトラップしたり、TSTPを誰にも送ってはいけません。

ジョブが生成され、停止したときに検出して(フォアグラウンドグループを取り消し、内部的に中断してジョブをマークする)ジョブの場合は、ちょうどwait()にする必要があります。あなたのfgコマンドは、ジョブのは、再びフォアグラウンドプロセスグループをにpgid作成し、それにSIGCONTを送信し、再びそれを待つ、bgはちょうどSIGCONT

+1

返信いただきありがとうございます。あなたが言うことをやってみましたが、シグナルハンドラを取り除くと、端末は親プロセスを一時停止し、bashに戻ります。私は親を走らせ続けなければならない。 – user1710304

+1

これは間違ったことですが、SIGTSTPを捕捉しても、シェルが中断し、子プロセスが続行されることはありません。 彼はそれを捕まえる必要がありますので、シェルは中断しません。 私は前に直面した同じ問題に直面しています – Fingolfin

+1

@AdelQodmani Ctrl-Zを押すと、端末のフォアグラウンドプロセスグループだけがSIGTSTPを受信します。起動したプロセスの終了を待っているシェルは、端末のフォアグラウンドプロセスグループではないプロセスグループ内にあります。もしあなたが好きなら、_ignore_ SIGTSTPすることができます。それは、ほとんどのシェルがすることでしょう。私の要点は、端末のフォアグラウンドプロセスグループで遊ぶ必要があるということでした。 –

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()関数はまだ待機中です!

これを行う正しい方法は、親のwait()をpause()に置き換え、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キー + Z親プロセスもSIGCHLDポーズ()リターンを受け取る受信した後。

0

私はここで質問に答えるのが遅くなるかもしれませんが、これは私が同じ問題を抱えていたときに働いたものです。tcsetpgrpのマニュアルページ()

関数とtcsetpgrp()に従っての制御端末でなければならないfdに関連付けられた端末のフォアグラウンドプロセスグループ、 PGRPプロセスグループID とプロセスグループを作ります呼び出しプロセス、および は依然としてそのセッションに関連付けられています。さらに、pgrpは、 プロセスと同じセッションに属する (空でない)プロセスグループでなければなりません。 tcsetpgrp()が そのセッションでバックグラウンドプロセスグループのメンバーによって呼び出され、呼び出しプロセスがブロックまたは SIGTTOUを無視していない場合

は、SIGTTOU信号はこのような背景 プロセスグループのすべてのメンバーに送信されます。

したがって、フォアグラウンドになるプロセスを作成する前に、シェルプログラムのSIGTTOUというシグナルを無視していました。このシグナルを無視しなければ、カーネルはこのシグナルを私のシェルプログラムに送り、それを中断します。

関連する問題