1.9.3から2系列にやっと重い腰を上げて移行を始めた鈴木と申します。

移行中にもしかしたらバグかもしれない現象にあったので報告いたします。もう2.2がリリースされているので、仕様の変更によるものでこれが設計通りの動作なのだとは思いますが、一応。

# 現象

Thread内で作成した子プロセスが終了してもSIGCHLDが親プロセスに送られてこない。

子プロセスが終了すると送られてくるSIGCHLDをtrapしてwaitすることで子プロセスがゾンビ化するのを防ぎたいのですが、Thread内で作成すると子プロセスが終了してもSIGCHLDをtrapすることができません。

またProcess.detach()を使ってみたのですが、Thread内だと同様にゾンビになってしまいました。

この現象はRubyのバージョンに依存しています。2.0と2.1ではこの問題が起きますが、1.9.3ではThread内でプロセスを作成しても、SIGCHLDを捕まえられます。

# テスト環境

Ubuntu 14.04.1
  ruby 1.9.3p484 (2013-11-22 revision 43786) [x86_64-linux]
SIGCHLDを捕まえられる。

Ubuntu 14.04.1
  ruby 2.0.0p384 (2014-01-12) [x86_64-linux-gnu]
Ubuntu 14.10
  ruby 2.1.2p95 (2014-05-08) [x86_64-linux-gnu]
SIGCHLDを捕まえられない。

# テストプログラム

#!/usr/bin/ruby
# -*- coding: utf-8 -*-

Signal.trap(:CHLD){
  begin
    while status = Process.waitpid2(-1, Process::WNOHANG|Process::WUNTRACED)
      print "SIGCHLD: pid_#{status.first}: #{status.last.inspect}\n"
    end
  rescue Errno::ECHILD
    print "SIGCHLD: Errno::ECHILD\n"
  end
}

def spawn_proc(from)
  if pid = fork
    print "spawn proc(#{pid})\n"
    # Process.detach(pid) # not work
  else
    sleep 1

    server(from)
    exit
  end
end

def server(from)
  print "#{$$}: forked in #{from}\n"
  sleep rand(10)
  print "#{$$}: exit\n"
  exit
end

Thread.start{
  3.times{
    spawn_proc("thread")
  }
}

3.times{
  spawn_proc("main")
}

sleep 30

-- 
鈴木教郎