From b93dc848835f93efc100cde2d3056512e7ddf557 Mon Sep 17 00:00:00 2001 From: normal Date: Sun, 8 Jul 2018 00:02:27 +0000 Subject: signal.c: preserve trap(:CHLD, "IGNORE") behavior with SIGCHLD We need to preserve "IGNORE" behavior from Ruby 2.5 and earlier. We can't rely on SA_NOCLDWAIT any more, since we always need system() and MJIT to work; so we fake that behavior using dedicated reaper (currently in timer-thread). git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63879 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- process.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) (limited to 'process.c') diff --git a/process.c b/process.c index 67883e0af2..f1e013a284 100644 --- a/process.c +++ b/process.c @@ -935,6 +935,7 @@ waitpid_notify(struct waitpid_state *w, rb_pid_t ret) # define waitpid_sys(pid,status,options) do_waitpid((pid),(status),(options)) #endif +extern volatile unsigned int ruby_nocldwait; /* signal.c */ /* called by timer thread */ static void waitpid_each(struct list_head *head) @@ -973,6 +974,11 @@ ruby_waitpid_all(rb_vm_t *vm) if (list_empty(&vm->waiting_pids)) { waitpid_each(&vm->waiting_grps); } + /* emulate SA_NOCLDWAIT */ + if (list_empty(&vm->waiting_pids) && list_empty(&vm->waiting_grps)) { + while (ruby_nocldwait && do_waitpid(-1, 0, WNOHANG) > 0) + ; /* keep looping */ + } rb_native_mutex_unlock(&vm->waitpid_lock); } @@ -1153,10 +1159,18 @@ rb_waitpid(rb_pid_t pid, int *st, int flags) } if (st) *st = w.status; - if (w.ret > 0) { - rb_last_status_set(w.status, w.ret); + if (w.ret == -1) { + errno = w.errnum; + } + else if (w.ret > 0) { + if (ruby_nocldwait) { + w.ret = -1; + errno = ECHILD; + } + else { + rb_last_status_set(w.status, w.ret); + } } - if (w.ret == -1) errno = w.errnum; return w.ret; } @@ -4306,16 +4320,22 @@ rb_f_system(int argc, VALUE *argv) struct rb_execarg *eargp; execarg_obj = rb_execarg_new(argc, argv, TRUE, TRUE); + TypedData_Get_Struct(execarg_obj, struct rb_execarg, &exec_arg_data_type, eargp); + eargp->nocldwait_prev = ruby_nocldwait; + ruby_nocldwait = 0; pid = rb_execarg_spawn(execarg_obj, NULL, 0); #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV) if (pid > 0) { int ret, status; ret = rb_waitpid(pid, &status, 0); - if (ret == (rb_pid_t)-1) + if (ret == (rb_pid_t)-1) { + ruby_nocldwait = eargp->nocldwait_prev; + RB_GC_GUARD(execarg_obj); rb_sys_fail("Another thread waited the process started by system()."); + } } #endif - TypedData_Get_Struct(execarg_obj, struct rb_execarg, &exec_arg_data_type, eargp); + ruby_nocldwait = eargp->nocldwait_prev; if (pid < 0) { if (eargp->exception) { int err = errno; -- cgit v1.2.3