なぜ、waitpidをループ処理させるのか
mruby-ioにissueを挙げたら思った以上に勉強させてもらえた件
前回のブログ記事への多くのブクマありがとうございました! まだ、前回の件で勉強になった事で書ききれていないことがあり、忘れないように記事にしておきます。
trusterdへのプルリク修行を指せてもらっているので、ここはひとつプルリクでもぼちぼち書き始めるかぁと 思ってもいたが、速攻で、対応されていた。
折角、対応して貰えたので、どういう対応なのか勉強させてもらおうと、コードを眺めた。
なんでdo-whileでwaitpidをチェックしているんだろ?
do { pid = waitpid(fptr->pid, NULL, 0); } while (pid == -1 && errno == EINTR);
waitpidは子プロセスが終了するまで、待ってくれるからループする必要が 何であるのだろ?
学んだこと
いくつかのシステムコールは、コール実行中に割り込みを受け、erronoにEINTERを設定することが あるので、再度、システムコールを実行した方が良い場合がある。という事だった。
Linux で、write(2) や close(2) を呼んだらエラー EINTR が発生… - 人力検索はてな や closeがEINTRを返したらどうするべきか - Togetterまとめ
のやり取りで分かった。
なんで割り込み受けるのかを考えてみた
mruby-ioを使っているプログラムで、signalを扱う場合、waitpidをコールしていた場合signalを受けると、登録済みのシグナルハンドラの 実行後、このwaitpidコールが中断される。
すると、このままでは、子プロセスが終了しても、修正前と同様に残ってしまう。
これを避ける為に、waitpidの戻り値がEINTRで合ったら、再度実行しているようだ。
また、返されるpidの値はmanによると
If an error is detected or a caught signal
aborts the call, a value of -1 is returned and errno is set to indicate the error.
とあるので、シグナルによる割り込みが発生した場合、-1がセットされるので、これも条件に含めていた。
mruby-ioのようなライブラリでは、さまざまな使われ方があり、これらの考えられうるユースケースのすべてにおいて、 正しく振る舞えるようにする必要があり、これを踏まえた実装であったのだ。
自前のアプリを作る際と比べ、ライブラリを作る際は、さらに多くの考慮が必要だという事が分かった。
勉強になりました。ありがとうございます。
関連記事
- libtrusterdのldd機能の負荷テストが失敗したことで子プロセスの扱いが少し理解が進んだ件
- mrubyでHTTP/1.1のKeep-Aliveで複数回リクエストを出してみた
- mrubyのFile.openをちょっと調べたメモ
- mruby-ioでclose_writeを実装したが、不要だった件
- WindowsでDLLを作ろうとしてmrb_context_runの歴史を調べた