posix_spawn は子プロセスを起動する関数なので、できるできないというのは子プロセスの属性をどう制御できるかというのが基本である。
posix_spawn は POSIX 2004 (IEEE Std 1003.1, 2004) で導入され、以下の属性を設定できる。これは IEEE Std 1003.1-2008 でも変わっていない
OS によっては独自拡張もある。見つけられた範囲では以下が存在する。(プロセスの属性を設定する以外の機能もある)
プロセスの属性はこれだけかというと、もちろんそうではない。指定できない属性としては、たとえば以下があげられるだろう。
プロセス属性には OS固有のものもある。
現実的には、working directory が指定できないことがよく問題になるようだ。
いずれにせよ、すべてのプロセス属性を posix_spawn で指定可能な OS は見当たらない。(そのようにする方向性の OS さえ見当たらない)
また、指定できる属性でも、不完全なことがある。
いろいろなプロセスの属性を設定しコマンドを実行するには、様々な失敗の機会があるが、失敗したときの posix_spawn の挙動も問題である。
まず、POSIX としては失敗した時に、posix_spawn が失敗するのと、posix_spawn は成功して子プロセスが exit status 127 で終了するのと、どちらの挙動も許している。でも、exit status は wait しないと取得できず、起動したプロセスがすぐに終わらないかもしれない場合には、wait すると長期間ブロックしてしまうので困る。
そして、失敗がちゃんと posix_spawn の失敗になる実装でも、わかるのは errno だけで、どこで (どのシステムコールで) が失敗したのかは分からない。
あと、posix_spawn は古い環境に存在しないという問題もなくはないかな。
もし、OS の立場から posix_spawn を勧めるなら、なにはともあれ、すべてのプロセス属性を指定可能にするくらいの気概は見せていただきたいところだ。実装がないと POSIX にも入らないし。
Ruby では現在プロセスの起動に vfork()/fork() を使っているが、これはもともと fork() を使っていたからである。なぜ fork() を使っていたかといえば、それは posix_spawn() より Ruby のほうが古いからだろう。
まぁ、これから posix_spawn に全面移行することはないだろうな。できないことがいろいろとあって、Ruby 側で対応できないから。
Solaris の posix_spawn_file_actions_addclosefrom_np() は本当に不要な fd をすべて close させるのに使えるだろうか。
考えてみると、あまり自明ではない。
0,1,2,4 が必要な fd だとすると、5以降を close するのは posix_spawn_file_actions_addclosefrom_np() で可能として、3をどうするかが問題である。
3 がもともと open されていれば posix_spawn_file_actions_addclose() で指定すればよい。
しかし、close されていた場合でも、他のスレッドやシグナルハンドラが絶妙なタイミングで open する可能性を否定できないので、念のために close しなければならない。ところが、close されている状態で posix_spawn_file_actions_addclose() で指定すると posix_spawn() 内で close() が失敗して、posix_spawn() 自体が失敗するかもしれない。が、Solaris の posix_spawn_file_actions_addclose() の man を読むと、これは失敗しないと明記されている。ちゃんと考えられているようだ。
SUSv4 の記述だと close の失敗も posix_spawn() の失敗 (あるいは子プロセスの exit status 127) になる感じだが。
まぁ、posix_spawn_file_actions_adddup2() で fd を open 状態にした後に posix_spawn_file_actions_addclose() とすれば、SUSv4 どおりの挙動でもどうにかなるか。
Mac OS X の POSIX_SPAWN_CLOEXEC_DEFAULT のほうがやりたいことに対して素直で良いな。
[latest]