In article <E13zgAK-0005kt-00 / ev.netlab.zetabits.co.jp>,
  matz / zetabits.com (Yukihiro Matsumoto) writes:

> |あと、fork した子プロセス内で、(exec 前に)いくつかのファイルを close
> |したいのですが、そのファイルを使っているスレッドが他にあると close 時
> |にそのスレッドで例外が発生してしまいます。これを防ぐ方法はないでしょう
> |か?
> |
> |close-on-exec すればいいのではないか、とも思ったのですが、socket など
> |は内部的に dup して 2つ file descriptor を使っているようで、 dup した
> |ものに close-on-exec を設定することができませんでした...
> 
> むむ、ちょっとシチュエーションが想像しきれませんでした。なん
> らかの対応をしたいのですが、現時点ではどのような対応が望まし
> いのか判断できません。

えぇと、unix domain socket である種の non-forking server を作っている
のですが、時おり、その中から外部のコマンドを起動する必要があります。
ここで何も考えずに fork/exec を使ってコマンドを起動すると、server が保
持している UNIXServerだの UNIXSocket だの(に対応する filede scriptor)
が継承されるわけです。そして、このコマンドは長い間生き残るので、トラブ
ル(EOF が検出不能になる)が起きます。

# http://cvs.m17n.org/~akr/cvsconnect/ というのがその shell script に
# よる実装で、これはこれで shell script の可能性を再発見できたという意
# 味ではとても面白かったのですが、いろいろとあまりにあんまりなので
# Ruby で作りなおしているのです。

で、close さえできれば解決するわけですが、

1. 普通に IO#close するとその file descriptor を待っているスレッドに
   IOError が発生する。

  ちゃんと IOError を全部捕まえれば動くんじゃないかとは思うのですが、
  いまのところ成功していません。いまひとつ何が起きているの把握できなく
  て...

2. close-on-exec を設定しておく。

  IO#fcntl では (OpenFile の)f2 を扱えないのでうまくいきません。そもそ
  も、なぜ UNIXServer や UNIXSocket はわざわざ dup して f2 を設定する
  のか、というのも疑問ですが... half close な状態を表現するため?

  # ついでにいえば socketpair がある環境では rw な popen でも f2 は使
  # わないでほしい。

3. IO.popen で我慢する。

  close する範囲が(私の環境では) 3 - 64 と固定。
  64 を越えると変なことが起こると思う。(limit descriptors は 1064)

というように、とりあえず 3つ思いついて調べて見たのですが、どれもうまく
ありません。

fcntl(など)を f2 に発行できるようにするか、
fork した当の thread 以外の thread をすべて有無を言わさず殺すような fork
(Thread.fork_and_kill_other_threads とか?)があるといいんじゃないかなぁ、
と思っています。

# ちなみに、最初は、sendmsg/recvmsg(ないしは ioctl)による file
# descriptor の受渡しも検討したのですが、ruby/perl/python のどれでも使
# えなさそうだったので断念しました。
-- 
[田中 哲][たなか あきら][Tanaka Akira]
「くっだらないコト聞いちゃったねー$(C⊇ ごっめーん$(C⊇」
  (魔法使い養成専門 マジックスター学院 2, 南澤ミヅキ)