Would you have time to turn that into a (tested ;) ) patch?
With attached patch on top of 1.9.3~preview1+svn33077-3 "make test" #244 test_fork.rb:51:in `<top (required)>': a = [] trap(:INT) { a.push(1) } trap(:TERM) { a.push(2) } pid = $$ begin fork do sleep 0.5 Process.kill(:INT, pid) Process.kill(:TERM, pid) end sleep 1 a.sort rescue NotImplementedError [1, 2] end #=> "[]" (expected "[1, 2]") [ruby-dev:44005] [Ruby 1.9 - Bug #4950] #934 test_thread.rb:389:in `<top (required)>': open("zzz.rb", "w") do |f| f.puts <<-END begin m = Mutex.new Thread.new { m.lock; sleep 1 } sleep 0.3 parent = Thread.current Thread.new do sleep 0.3 begin fork { GC.start } rescue Exception parent.raise $! end end m.lock pid, status = Process.wait2 $result = status.success? ? :ok : :ng rescue NotImplementedError $result = :ok end END end require "./zzz.rb" $result #=> "" (expected "ok") FAIL 2/937 tests failed make: *** [yes-btest-ruby] Error 1
--- ruby1.9.1-1.9.3~preview1+svn33077.orig/thread_pthread.c +++ ruby1.9.1-1.9.3~preview1+svn33077/thread_pthread.c @@ -1045,6 +1045,36 @@ static pthread_t timer_thread_id; static int timer_thread_pipe[2] = {-1, -1}; static int timer_thread_pipe_owner_process; +#if 0 +static inline int +timer_thread_running() { + return timer_thread_pipe_owner_process == getpid() ? 1 : 0; +} + +static inline void timer_thread_set() { + timer_thread_pipe_owner_process = getpid(); +} + +RUBY_FUNC_EXPORTED +void timer_thread_child_at_fork() { +}; + +#else +static inline int +timer_thread_running() { + return timer_thread_pipe_owner_process; +} + +static inline void timer_thread_set() { + timer_thread_pipe_owner_process = 1; +} + +RUBY_FUNC_EXPORTED +void timer_thread_child_at_fork() { + timer_thread_pipe_owner_process = 0; +}; +#endif + #define TT_DEBUG 0 #define WRITE_CONST(fd, str) (void)(write((fd),(str),sizeof(str)-1)<0) @@ -1056,7 +1086,7 @@ rb_thread_wakeup_timer_thread(void) ssize_t result; /* already opened */ - if (timer_thread_pipe_owner_process == getpid()) { + if (timer_thread_running()) { const char *buff = "!"; retry: if ((result = write(timer_thread_pipe[1], buff, 1)) <= 0) { @@ -1199,7 +1229,7 @@ rb_thread_create_timer_thread(void) #endif /* communication pipe with timer thread and signal handler */ - if (timer_thread_pipe_owner_process != getpid()) { + if (!timer_thread_running()) { if (timer_thread_pipe[0] != -1) { /* close pipe of parent process */ close_communication_pipe(); @@ -1229,7 +1259,7 @@ rb_thread_create_timer_thread(void) #endif /* defined(HAVE_FCNTL) && defined(F_GETFL) && defined(F_SETFL) */ /* validate pipe on this process */ - timer_thread_pipe_owner_process = getpid(); + timer_thread_set(); } /* create timer thread */ --- ruby1.9.1-1.9.3~preview1+svn33077.orig/main.c +++ ruby1.9.1-1.9.3~preview1+svn33077/main.c @@ -21,6 +22,8 @@ RUBY_GLOBAL_SETUP +extern void timer_thread_child_at_fork(); + int main(int argc, char **argv) { @@ -31,6 +34,10 @@ main(int argc, char **argv) setlocale(LC_CTYPE, ""); #endif +#if 1 + pthread_atfork(NULL, NULL, timer_thread_child_at_fork); +#endif + ruby_sysinit(&argc, &argv); { RUBY_INIT_STACK;