summaryrefslogtreecommitdiff
path: root/process.c
diff options
context:
space:
mode:
authornormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-07-08 00:02:27 +0000
committernormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-07-08 00:02:27 +0000
commitb93dc848835f93efc100cde2d3056512e7ddf557 (patch)
tree7e82c88368a5101d28ae9eade99e2b5831412ec8 /process.c
parent4719a45483fe7716e81b6f22c2f8f6b41dfb8d58 (diff)
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
Diffstat (limited to 'process.c')
-rw-r--r--process.c30
1 files changed, 25 insertions, 5 deletions
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;