Lions’ Commentary on UNIX 読書会メモ#6

はじめに

Lions本読書会#6に参加してきました。メモを残しておきます。

当初は13, 14章を読む予定でしたが、議論が白熱して13章の前半(トレースの前)までで時間が来てしまいました。

進度は遅かったですが、今までで一番盛り上がった会とも言えそうです。

さらにPDP11+Unix v6インタプリタを実装した参加者のデモまでありました(!!)

togetter

関連ツイートをtogetterでまとめました。


ツイートが活発だったので、これを読むだけでも当日話された内容がつかめると思います。

exit( ) & wait( )

今回一番話題になったのがexit( )のloop:以降の内容でした。init processを起こしていたり、子プロセスの親プロセスをinit processに切り替えていたり。「いったい何のためにこんなことをしているんだ?」と疑問が飛び交いました。

議論の内容を基に、絵でまとめてみました。

exit( )の実行

下図のような親子関係のときに、プロセス4がexit( )を呼んだとします。

自分をZOMBIEにした後、親プロセスであるプロセス3とinitプロセスであるプロセス1を起こします。

その後、子プロセスであるプロセス5, 6, 7の親をプロセス1に変更します(養子に出している?)。

最後にswtch( )を呼び出して実行プロセスを切り替えます。

親プロセスであるプロセス3が選択された時とinitプロセスであるプロセス1が選択された時をそれぞれ見ていきます。

swtch( )で親プロセスが選択された時

wait( )内のsleep( )(3314行目)で寝ていた場所から処理を再開します。loop(3276行目)に戻り、子プロセスであるZOMBIE状態のプロセスを始末します。始末した後、親プロセスはwait( )を呼び出した場所に戻り、処理を続けます。


このように、exit( )を呼び出した自分自身を始末してもらうためにwakeup( p )で親プロセスを起こしたのです。

swtch( )でinitプロセスが選択された時

wait( )内のsleep( )(3314行目)で寝ていた場所から処理を再開します。loop(3276行目)に戻り、(養子にもらった)子プロセスがZOMBIE状態だったら始末します。exit( )内で、子プロセスがbreak pointで止まった状態だったらsetrun( )でSRUN状態にしているので、子プロセスがSSTOP状態であることはないと思います。(ただし、時間が経ってからinitプロセスが選択された場合、ありうる?)

本来は「子プロセスがexit( )で終了した後、親プロセスであるプロセス4がwait( )内でその子プロセスを始末する」ことを想定しているのですが、なんらかの事情で親プロセス4が子プロセスを始末する前に自分自身をexit( )で終了させてしまった場合、子プロセスがZOMBIE状態のまま放ったらかしにされてしまうので、子プロセスをinitプロセスに養子に出し、後を任せているのだと思います。

子プロセスがZOMBIEでなかった場合、そのまま生き続けるようです。ただし、これらのプロセスがトレース状態(p_flagのSTRCフラグがON)だった場合、issig( )を実行した際3999行目からstop( )に飛び、4032行目で自分自身を終了させます。これは、介入する予定だった親プロセスが既にいないためだと思います。


このように、子プロセスの後始末をしてもらうためにwakeup( &proc[ 1 ] )でinitプロセスを起こしたのです。

参考:init.c

initプロセスの本体ともいえるinit.cが勉強会で紹介されました。


中を見ると、for(ever)のところで無限ループに入っています。initプロセスに複数のZOMBIEが養子に出されたとしても、wait( )を繰り返し実行して一つずつ始末していくようです。(wait( )ではZOMBIEを一つ始末するとreturnで戻ってしまう(3299行目)ので、このようにしないと始末のし損ないが起きてしまいます(たぶん))

参考:wakeup( &proc[ 1 ] )でinitプロセス(proc[ 1 ])が起きる理由

wakeup( )を見ると(2113行目)、引数で渡したプロセスを起こすのではなく、引数で渡した理由(プロセスとは限らない)で寝ているプロセスを起こす関数であることがわかります。

では、なぜwakeup( &proc[ 1 ] )でproc[ 1 ]が起きるのでしょうか。

上記init.cを見ると、initはfor(ever)のwait( )(このwait( )はCの関数。システムコールwaitを引き起こす)で止まっていると思われます。wait( )(これはシステムコールハンドラ。3270行目)を見ると、3314行目でsleep( u.u_procp, PWAIT )で寝ていることがわかります。つまり、自分自身を理由に寝ています。よってwakeup( &proc[ 1 ] )でinitプロセス(proc[ 1 ])が起きるのです。

終わりに

次回のLions本読書会は5月28日(土)に開催されます。「OSのコード読んでみたい!」という方は参加してみてはいかがでしょうか。