katsuhiro > katsuhiro/refmon > katsuhiro/refmon/wait
sys_pid と sys_wait4 のエミュレーション†
ptrace すると本来の親が子を wait できなくなるため、リファレンスモニタが sys_waitpid と sys_wait4 のエミュレーションを行う必要がある。
- システムコールの番号には sys_waitpid と sys_wait4 があるが、sys_waitpid は内部で sys_wait4 を呼び出しているだけである。
- カーネルのコードをパクると、後でライセンスなどややこしいかもしれない。今のところ GPL のコードは使っていない。ただ独自実装ゆえに色々おかしいかもしれない。
2.4系と 2.6系の違い†
ptrace しているときの wait の動きが違う。
たとえば make している途中で Ctrl+C を押したとき。
- 2.4
- waitpid in
- waitpid out(-ECHILD)
- 2.4系では wait 系の関数がすぐ帰ってくる。
- (処理)
- SIGINT
- 2.6
- waitpid in
- waitpid out(-ERESTARTSYS)
- read などで止まっている時にシグナルを送ったときと似たような動作になる。
- SIGINT
2.6系の問題†
waitpid(-1, &st, WUNTRACED); とやっているのに、ptrace してしまうと
子プロセスが止まっても戻ってこなくなる?
wait 系をエミュレーションしないと起こる問題†
- make が動かない。子プロセスがない、と言って終了してしまう。
- xterm やシェルも子プロセスが把握できなくなって、表示が崩れる。top などすぐに終わらない、画面を占領するソフトウェアはさらに崩れる。
実装でつまづいたこと†
- 問題: サスペンドが効かない、一部のソフトウェアで動作がおかしくなる。
- 同様の問題: sleep が途中で割り込まれて終了(EINTR が返ってくる)して、本来と異なる動作をする。
- 原因: デフォルトで無視されるシグナル、キャッチされるシグナルなどの判定をしていない。または本来ならばマスクしているはずのシグナルを送ってしまっている。
- 解決: sigprocmask や sigaction などのエミュレートが必要である。
sys_waitpid および sys_wait4 のエミュレーション(2.4系向け)の実装†
全部書くのは無理なので、流れだけ。
親プロセス†
- sys_waitpid あるいは sys_wait4 が呼ばれた。
- 最後に作成した子プロセス(末っ子と呼ぶ)から、状態変化がおきていないかどうか調べて、兄が居ればそれらも調べる。
- どの子供にも当てはまらないなら、実行を停止させる。
- 停止したプロセスは、子供に状態変化がおきたときに再開される。
- 当てはまるなら、子供が止まったときのシグナルやリソース利用状況(wait4 のみ)などを監視対象のメモリ空間にコピーして、続行する。
- それらの情報はリファレンスモニタが保存しておかなければならない。
子プロセス†
- シグナルを受けて停止、あるいはプロセスが終了した。
- 親プロセスがいて、wait していれば、親に通知する。
- 親の wait 条件(上記のもの)を吟味して、当てはまるならば親を再開させる。
- 当てはまらないなら、そのまま止まる(あるいはゾンビになる)。