Skip to content

Commit

Permalink
add after_fork{} hook
Browse files Browse the repository at this point in the history
  • Loading branch information
tmm1 committed Nov 30, 2013
1 parent b057217 commit 711a68b
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 1 deletion.
23 changes: 23 additions & 0 deletions process.c
Original file line number Diff line number Diff line change
Expand Up @@ -3687,6 +3687,28 @@ rb_f_abort(int argc, VALUE *argv)
UNREACHABLE;
}


/*
* call-seq:
* after_fork{ puts "Forked #{Process.pid} from #{Process.ppid}" } -> proc
*
* Run block in child process after the VM forks.
*/

VALUE
rb_f_after_fork(VALUE self)
{
VALUE proc;
VALUE *hooks = &(GET_THREAD()->vm->after_fork);

rb_need_block();
proc = rb_block_proc();
if (!RTEST(*hooks)) *hooks = rb_ary_new();
rb_ary_push(*hooks, proc);
return proc;
}


void
rb_syswait(rb_pid_t pid)
{
Expand Down Expand Up @@ -7302,6 +7324,7 @@ Init_process(void)
rb_define_global_function("sleep", rb_f_sleep, -1);
rb_define_global_function("exit", rb_f_exit, -1);
rb_define_global_function("abort", rb_f_abort, -1);
rb_define_global_function("after_fork", rb_f_after_fork, 0);

rb_mProcess = rb_define_module("Process");

Expand Down
11 changes: 11 additions & 0 deletions test/ruby/test_process.rb
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,17 @@ def test_popen_fork
rescue NotImplementedError
end

def test_after_fork
assert_separately([], <<-END)
r, w = IO.pipe
after_fork{ w.write "Forked \#{Process.pid} from \#{Process.ppid}" }
Process.wait(child = fork{ exit })
w.close
assert_equal "Forked \#{child} from \#{Process.pid}", r.read
END
end

def test_fd_inheritance
skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows?
with_pipe {|r, w|
Expand Down
7 changes: 7 additions & 0 deletions thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -3915,11 +3915,18 @@ terminate_atfork_i(st_data_t key, st_data_t val, st_data_t current_th)
void
rb_thread_atfork(void)
{
VALUE hooks = GET_THREAD()->vm->after_fork;
long i;

rb_thread_atfork_internal(terminate_atfork_i);
GET_THREAD()->join_list = NULL;

/* We don't want reproduce CVE-2003-0900. */
rb_reset_random_seed();

if (RTEST(hooks))
for (i=0; i<RARRAY_LEN(hooks); i++)
rb_proc_call(RARRAY_AREF(hooks, i), rb_ary_new());
}

static int
Expand Down
1 change: 1 addition & 0 deletions vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1607,6 +1607,7 @@ rb_vm_mark(void *ptr)
RUBY_MARK_UNLESS_NULL(vm->top_self);
RUBY_MARK_UNLESS_NULL(vm->coverages);
RUBY_MARK_UNLESS_NULL(vm->defined_module_hash);
RUBY_MARK_UNLESS_NULL(vm->after_fork);
rb_gc_mark_locations(vm->special_exceptions, vm->special_exceptions + ruby_special_error_count);

if (vm->loading_table) {
Expand Down
2 changes: 1 addition & 1 deletion vm_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ typedef struct rb_vm_struct {
* objects so do *NOT* mark this when you GC.
*/
struct RArray at_exit;

VALUE after_fork;
VALUE *defined_strings;

/* params */
Expand Down

0 comments on commit 711a68b

Please sign in to comment.