2016-11-06 1 views
3

現在、私はシェルを作っていて、実行するフォアグラウンドプロセスでうまく動作します。今私はバックグラウンドプロセスとジョブコントロールを実装しなければなりません。私はそれにどのようにアプローチすべきかについて正直に混乱しています。私はバックグラウンドでプロセスを実行したい場合、私は彼らのpgidを設定し、単にそれらを待つことはありませんが、私はそれらを収穫しようとするときに壁を打つ必要があることを理解...シェルでバックグラウンドプロセスを獲得するSIGCHLDのシグナルハンドラを作成するには?

私は2つの構造:そして

typedef struct job { 
    int is_background_job; 
    pid_t pgid; 
    int job_status; 
    process *p;   // List of processes to execute for this job 
    struct job *next; // If a background job, it will be in a global linked list of job structs 
} job; 

typedef struct process { 
    char **argv; 
    process *next;  // The next process to pipe to 
} process; 

重要な部分は、ジョブは、プロセス構造体のリンクリストで構成されていることで、私のバックグラウンドジョブのすべてが起こって表しジョブ構造体のグローバルリストがあることを処理します。

シェルアルゴリズムは一種の標準です。

シェル:

get cmd from terminal 
parse cmd and create a job struct filled with processes 
if job is a background job: 
    add it to global background job list 
fork(), setpgid, and do the piping in a while loop of the job's processes 
if job is a foreground process: 
    wait on the forked processes 
else: 
    don't wait // since it's a background process 
continue to loop and read next cmd from terminal 

は今ここに私の問題です。バックグラウンドで実行されているプロセスがたくさんある場合は、いずれかのバックグラウンドジョブのいずれかが終了してからSIGCHLDを送信できることを意味します。厄介な点は、特定のジョブのすべてのプロセスが終了した場合、そのジョブをグローバルジョブリストから削除する必要があるということです。私はシグナルハンドラ中にfinsihesを実行しているforgroundプロセスがオフチャンスであるため、ここで私のSIGCHLDハンドラでwaitpid(-1、&ステータス、WNOHANG)のループを呼び出すことはできません。

これは、すべてのジョブのすべてのプロセスでwaitpid()を実行しなければならないことを意味します。これは、SIGCHLDを取得するとただちに非fgプロセスで待機するようになっていますか?

私は本当にコードを必要としませんが、これを行う良い方法についての説明です。

+1

"シグナルハンドラ中に実行されているフォアグラウンドプロセスが現在実行中であることを示します。フォアグラウンドプロセスが終了したらどうなりますか?ちょうどそれを処理します。バックグラウンドリストには含まれないので、バックグラウンドプロセスではありません。 – kaylum

+1

シグナルハンドラ中にプロセスが終了しても、 'sigaction'を使ってマスクすることができ、isrの後に他のプロセスシグナルハンドラを処理することができます – Anjaneyulu

+0

遅い応答には残念です。しかし、kaylum、forgroundプロセスがforkの親がそれを待つ前にsighandlerで終了したら、forkpidがforkの後でforgroundプロセスのためにやっていることが永遠に止まるでしょうか? – ParadoxicalEnigma

答えて

1

これは本当に遅く、おそらく今あなたには間違いないと知っていますが、私もシェルで作業しており、この同じ問題を解明しようとしている間にあなたの質問に走りました。

とにかく、フォアグラウンドのすべての子供を待つためのメインプロセスが問題になっているようですが、これはハンドブックSIGCHLDwaitpidへの呼び出しにとって難しいことです。私がこれをしたのは、メインプロセスでwait()コールを使用する代わりに、ハンドラ内のすべてのプロセスを刈り取り、適切なリストから削除しました(現在、すべてのフォアグラウンドプロセスとすべてのバックグラウンドプロセスのリストがあります)。その後、私は、メインプロセスに:

while(foreground process list is not empty) 
    pause(); 

pause()コールはちょうどそれが信号によってウェイクアップされるまで、スリープ状態にプロセスを置き、それが再びかどうかを確認することができているので、この場合にはSIGCHLDは常にプロセスを呼び起こします待っている必要があるフォアグラウンドプロセスがまだ実行中です。これが誰かを助けることを願って!

編集:リストが空でないことを確認した直後に子が終了し、pause()に電話する前に競合状態が発生する可能性があることが分かりました。これを回避するには、単に休止する代わりにnanosleepを使用するだけですが、それでも信号によって中断されますが、定期的にリストのサイズを確認するオプションがあります。この場合、競合状態を回避します。

+0

ありがとう、少し前に課題を終えて少し遅れました。あなたが余計な努力をしたので、これをマークします。 – ParadoxicalEnigma

関連する問題