ふと、fork が失敗したときに ruby がどう振る舞うか調べてみた。
% ruby -v ruby 2.0.0dev (2012-01-10 trunk 34265) [x86_64-linux] % for n in {98..90} do ruby -e 'n = ARGV.shift.to_i; p n Process.setrlimit(:NPROC, n) pid = fork { p [:c, $$] } p [:p, pid] Process.wait pid ' $n done 98 [:p, 24982] [:c, 24982] 97 [:p, 24987] [:c, 24987] 96 [:p, 24992] [:c, 24992] 95 [:p, 24997] [FATAL] Failed to create timer thread (errno: 11) 94 [FATAL] Failed to create timer thread (errno: 11) [FATAL] Failed to create timer thread (errno: 11) 93 [FATAL] Failed to create timer thread (errno: 11) 92 [FATAL] Failed to create timer thread (errno: 11) 91 [FATAL] Failed to create timer thread (errno: 11) 90 [FATAL] Failed to create timer thread (errno: 11)
1.9 以降では、timer thread があるので、fork 直前には、プロセス内に main thread と timer thread のふたつがある。すべてがうまくいって子プロセスができると、子プロセス内にも main thread と timer thread のふたつができる。
とある理由により、親プロセスは fork system call を呼ぶ瞬間には timer thread を殺すので、まず親プロセスの timer thread が死んで、その後で子プロセスの main thread が生まれ、その後で親子両方で timer thread が生まれる。
結局 3つスレッドが生まれるので、(race condition を考慮しなければ) NPROC の値によって 4種類の挙動が観測できるはずで、そのとおりの結果になっている。
うまくいった場合:
96 [:p, 24992] [:c, 24992]
子プロセスの main thread と親プロセスの timer thread は生まれなかったが、子プロセスの timer thread は作れなかった:
95 [:p, 24997] [FATAL] Failed to create timer thread (errno: 11)
子プロセスの main thread は生まれたが、親子両方の timer thread は作れなかった:
94 [FATAL] Failed to create timer thread (errno: 11) [FATAL] Failed to create timer thread (errno: 11)
子プロセスを作れなかった:
93 [FATAL] Failed to create timer thread (errno: 11)
[latest]