12

私はミニシェルを書いています(いいえ、学校用ではありません:P;私自身の楽しみのために)そして基本的な機能のほとんどはこれで完了しましたが、SIGTSTPを処理しようとすると行き詰まります。

おそらく、ユーザーがを押すCtrl+Zと、SIGTSTPが存在する場合はシェルのフォアグラウンドプロセスに送信され、シェルは通常どおり続行する必要があります。

各プロセスを作成した後(フォアグラウンドプロセスの場合)、次のコードが待機します。

if(waitpid(pid, &processReturnStatus, WUNTRACED)>0){//wait stopped too
    if(WIFEXITED(processReturnStatus) || WIFSIGNALED(processReturnStatus))
        removeFromJobList(pid);
}

そして、私は次のように信号を処理しています:

void sigtstpHandler(int signum)
{
    signum++;//Just to remove gcc's warning
    pid_t pid = findForegroundProcessID();
    if(pid > -1){
        kill(-pid, SIGTSTP);//Sending to the whole group
    }
}

を押すCtrl+Zと、子プロセスは実際に中断されますが(プロセスの状態を表示するために使用)、フラグを渡してもps -allシェルがハングします。プロセスも停止します。 では、何が間違っている可能性がありますか?または、waitpidの動作を正しく理解していませんか?waitpidWUNTRACEDwaitpid

注:
-findForegroundProcessID()は正しいpidを返します。私はそれを再確認しました。
-直後に各プロセスのグループを変更しています-処理はfork
正常に機能Ctrl+Cしています
-シェルがハングした後に別の端末を使用してSIGCONTを送信すると、子プロセスは作業を再開し、シェルは最終的にそれを取得します。
-私が読んだ(そしてテストした)限り、捕まえることができるSIGTSTPを捕まえています。-念のため、waitpidの代わりにwaitidを使用してみましたが、問題が解決しませんでした。 編集:

void sigchldHandler(int signum)
{
    signum++;//Just to remove the warning
    pid_t pid;
    while((pid = waitpid(-1, &processReturnStatus, 0)) > 0){    
        removeFromJobList(pid);
    }
    if(errno != ECHILD)
        unixError("kill error");
}

私のSIGCHLDハンドラー。

4

2 に答える 2

1

SIGCHLD停止した子供のために配達されます。シグナルハンドラー(指定されていない)でのwaitpid()呼び出しは、永久にブロックされます。 WUNTRACED

removeFromJobList()おそらく、2つの異なる場所で処理するべきではありません。推測しなければならないのですが、それはグローバルなデータ構造に影響を与えているように聞こえ、シグナルハンドラーには属していません。

于 2012-12-26T00:55:17.620 に答える
1

sigchld ハンドラー (先ほどお送りしました) を設定していないため、waitpid が返されません。リープされていない子プロセスがあります。さらに、waitpid は if ではなく while ループにある必要があります (これも送信されました)。

キャッチする必要がある唯一のシグナルは SIGCHLD です。その理由は、プロセスが適切にフォークされている場合、カーネルはそのシグナルをフォアグラウンド プロセスに送信し、プロセスを終了または停止するか、シグナルが適切であることを何でも実行するためです。

プロセス グループが正しく設定されていないと、シグナルが間違ったプロセスに送信されます。これをテストする 1 つの方法は、フォアグラウンド プロセスを実行して Ctrl-Z を押すことです。シェル全体が存在する場合、Ctrl-Z シグナルがシェル全体に送信されます。これは、新しいプロセスを新しいプロセス グループに設定せず、ターミナルを与えたことを意味します。

Ctrl-Z シグナルがシェル全体を停止している場合は、次のことを行う必要があります。プロセスをフォークしたら、子プロセスで: - setpgid を使用してプロセスを独自のグループに設定します。- SIGTTOU をブロックし、tcsetpgrp を使用してターミナルを与えることにより、正常なターミナルを与えます。

親で: - setpgid を使用して子プロセスも設定します。これは、子と親のどちらが先に実行されるかわからないため、競合状態を回避するためです。2回設定しても問題ありません。

于 2012-12-26T09:45:56.107 に答える