diff options
author | naruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2018-07-04 15:08:56 +0000 |
---|---|---|
committer | naruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2018-07-04 15:08:56 +0000 |
commit | df4a126d65e4690e9301392974fcc9adf7d4c474 (patch) | |
tree | b7e28720d8dcdc42a4c4a0b607e29401d3e6aa62 /process.c | |
parent | 0f24cdec9ed4a2023b682e7cd5492b1602100b09 (diff) | |
download | ruby-df4a126d65e4690e9301392974fcc9adf7d4c474.tar.gz |
Revert r63758 and related commits
The change is unstable on Windows. Please re-commit it when it correctly
supports Windows.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63852 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'process.c')
-rw-r--r-- | process.c | 287 |
1 files changed, 43 insertions, 244 deletions
@@ -885,6 +885,12 @@ pst_wcoredump(VALUE st) #endif } +struct waitpid_arg { + rb_pid_t pid; + int flags; + int *st; +}; + static rb_pid_t do_waitpid(rb_pid_t pid, int *st, int flags) { @@ -897,263 +903,45 @@ do_waitpid(rb_pid_t pid, int *st, int flags) #endif } -struct waitpid_state { - struct list_node wnode; - rb_execution_context_t *ec; - rb_nativethread_cond_t *cond; - rb_pid_t ret; - rb_pid_t pid; - int status; - int options; - int errnum; -}; - -void rb_native_mutex_lock(rb_nativethread_lock_t *); -void rb_native_mutex_unlock(rb_nativethread_lock_t *); -void rb_native_cond_signal(rb_nativethread_cond_t *); -void rb_native_cond_wait(rb_nativethread_cond_t *, rb_nativethread_lock_t *); -rb_nativethread_cond_t *rb_sleep_cond_get(const rb_execution_context_t *); -void rb_sleep_cond_put(rb_nativethread_cond_t *); - -static void -waitpid_notify(struct waitpid_state *w, rb_pid_t ret) -{ - w->ret = ret; - list_del_init(&w->wnode); - rb_native_cond_signal(w->cond); -} - -#ifdef _WIN32 /* for spawnvp result from mjit.c */ -# define waitpid_sys(pid,status,options) \ - (WaitForSingleObject((HANDLE)(pid), 0),\ - GetExitCodeProcess((HANDLE)(pid), (LPDWORD)(status))) -#else -# define waitpid_sys(pid,status,options) do_waitpid((pid),(status),(options)) -#endif - -/* called by timer thread */ -static void -waitpid_each(struct list_head *head) -{ - struct waitpid_state *w = 0, *next; - - list_for_each_safe(head, w, next, wnode) { - rb_pid_t ret; - - if (w->ec) - ret = do_waitpid(w->pid, &w->status, w->options | WNOHANG); - else - ret = waitpid_sys(w->pid, &w->status, w->options | WNOHANG); - - if (!ret) continue; - if (ret == -1) w->errnum = errno; - - if (w->ec) { /* rb_waitpid */ - rb_thread_t *th = rb_ec_thread_ptr(w->ec); - - rb_native_mutex_lock(&th->interrupt_lock); - waitpid_notify(w, ret); - rb_native_mutex_unlock(&th->interrupt_lock); - } - else { /* ruby_waitpid_locked */ - waitpid_notify(w, ret); - } - } -} - -void -ruby_waitpid_all(rb_vm_t *vm) -{ - rb_native_mutex_lock(&vm->waitpid_lock); - waitpid_each(&vm->waiting_pids); - if (list_empty(&vm->waiting_pids)) { - waitpid_each(&vm->waiting_grps); - } - rb_native_mutex_unlock(&vm->waitpid_lock); -} - -static void -waitpid_state_init(struct waitpid_state *w, rb_pid_t pid, int options) -{ - w->ret = 0; - w->pid = pid; - w->options = options; -} - -/* - * must be called with vm->waitpid_lock held, this is not interruptible - */ -rb_pid_t -ruby_waitpid_locked(rb_vm_t *vm, rb_pid_t pid, int *status, int options, - rb_nativethread_cond_t *cond) -{ - struct waitpid_state w; - - assert(!ruby_thread_has_gvl_p() && "must not have GVL"); - - waitpid_state_init(&w, pid, options); - if (w.pid > 0 || list_empty(&vm->waiting_pids)) - w.ret = do_waitpid(w.pid, &w.status, w.options | WNOHANG); - if (w.ret) { - if (w.ret == -1) w.errnum = errno; - } - else { - w.cond = cond; - w.ec = 0; - list_add(w.pid > 0 ? &vm->waiting_pids : &vm->waiting_grps, &w.wnode); - do { - rb_native_cond_wait(w.cond, &vm->waitpid_lock); - } while (!w.ret); - list_del(&w.wnode); - } - if (status) { - *status = w.status; - } - if (w.ret == -1) errno = w.errnum; - return w.ret; -} - -static void -waitpid_wake(void *x) -{ - struct waitpid_state *w = x; - - /* th->interrupt_lock is already held by rb_threadptr_interrupt_common */ - rb_native_cond_signal(w->cond); -} - static void * -waitpid_nogvl(void *x) +rb_waitpid_blocking(void *data) { - struct waitpid_state *w = x; - rb_thread_t *th = rb_ec_thread_ptr(w->ec); - - rb_native_mutex_lock(&th->interrupt_lock); - /* - * We must check again before waiting, timer-thread may change w->ret - * by the time we enter this. And we may also be interrupted. - */ - if (!w->ret && !RUBY_VM_INTERRUPTED_ANY(w->ec)) { - if (SIGCHLD_LOSSY) { - rb_thread_wakeup_timer_thread(); - } - rb_native_cond_wait(w->cond, &th->interrupt_lock); - } - rb_native_mutex_unlock(&th->interrupt_lock); - - return 0; + struct waitpid_arg *arg = data; + rb_pid_t result = do_waitpid(arg->pid, arg->st, arg->flags); + return (void *)(VALUE)result; } -static VALUE -waitpid_sleep(VALUE x) -{ - struct waitpid_state *w = (struct waitpid_state *)x; - - while (!w->ret) { - rb_thread_call_without_gvl(waitpid_nogvl, w, waitpid_wake, w); - } - - return Qfalse; -} - -static VALUE -waitpid_cleanup(VALUE x) -{ - struct waitpid_state *w = (struct waitpid_state *)x; - - if (w->ret == 0) { - rb_vm_t *vm = rb_ec_vm_ptr(w->ec); - - rb_native_mutex_lock(&vm->waitpid_lock); - list_del(&w->wnode); - rb_native_mutex_unlock(&vm->waitpid_lock); - } - rb_sleep_cond_put(w->cond); - - return Qfalse; -} - -static void -waitpid_wait(struct waitpid_state *w) -{ - rb_vm_t *vm = rb_ec_vm_ptr(w->ec); - - /* - * Lock here to prevent do_waitpid from stealing work from the - * ruby_waitpid_locked done by mjit workers since mjit works - * outside of GVL - */ - rb_native_mutex_lock(&vm->waitpid_lock); - - if (w->pid > 0 || list_empty(&vm->waiting_pids)) - w->ret = do_waitpid(w->pid, &w->status, w->options | WNOHANG); - if (w->ret) { - w->cond = 0; - if (w->ret == -1) w->errnum = errno; - } - else if (w->options & WNOHANG) { - w->cond = 0; - } - else { - w->cond = rb_sleep_cond_get(w->ec); - /* order matters, favor specified PIDs rather than -1 or 0 */ - list_add(w->pid > 0 ? &vm->waiting_pids : &vm->waiting_grps, &w->wnode); - } - - rb_native_mutex_unlock(&vm->waitpid_lock); - - if (w->cond) { - rb_ensure(waitpid_sleep, (VALUE)w, waitpid_cleanup, (VALUE)w); - } -} - -static void * -waitpid_blocking_no_SIGCHLD(void *x) -{ - struct waitpid_state *w = x; - - w->ret = do_waitpid(w->pid, &w->status, w->options); - - return 0; -} - -static void -waitpid_no_SIGCHLD(struct waitpid_state *w) +static rb_pid_t +do_waitpid_nonblocking(rb_pid_t pid, int *st, int flags) { - if (w->options & WNOHANG) { - w->ret = do_waitpid(w->pid, &w->status, w->options); - } - else { - do { - rb_thread_call_without_gvl(waitpid_blocking_no_SIGCHLD, w, - RUBY_UBF_PROCESS, 0); - } while (w->ret < 0 && errno == EINTR && (RUBY_VM_CHECK_INTS(w->ec),1)); - } - if (w->ret == -1) - w->errnum = errno; + void *result; + struct waitpid_arg arg; + arg.pid = pid; + arg.st = st; + arg.flags = flags; + result = rb_thread_call_without_gvl(rb_waitpid_blocking, &arg, + RUBY_UBF_PROCESS, 0); + return (rb_pid_t)(VALUE)result; } rb_pid_t rb_waitpid(rb_pid_t pid, int *st, int flags) { - struct waitpid_state w; + rb_pid_t result; - waitpid_state_init(&w, pid, flags); - w.ec = GET_EC(); - - if (RUBY_SIGCHLD || SIGCHLD_LOSSY) { - waitpid_wait(&w); + if (flags & WNOHANG) { + result = do_waitpid(pid, st, flags); } else { - waitpid_no_SIGCHLD(&w); + while ((result = do_waitpid_nonblocking(pid, st, flags)) < 0 && + (errno == EINTR)) { + RUBY_VM_CHECK_INTS(GET_EC()); + } } - - if (st) *st = w.status; - if (w.ret > 0) { - rb_last_status_set(w.status, w.ret); + if (result > 0) { + rb_last_status_set(*st, result); } - if (w.ret == -1) errno = w.errnum; - return w.ret; + return result; } @@ -3807,8 +3595,6 @@ disable_child_handler_fork_child(struct child_handler_disabler_state *old, char } } - /* non-Ruby child process, ensure cmake can see SIGCHLD */ - sigemptyset(&old->sigmask); ret = sigprocmask(SIG_SETMASK, &old->sigmask, NULL); /* async-signal-safe */ if (ret != 0) { ERRMSG("sigprocmask"); @@ -4300,6 +4086,16 @@ rb_f_system(int argc, VALUE *argv) VALUE execarg_obj; struct rb_execarg *eargp; +#if defined(SIGCLD) && !defined(SIGCHLD) +# define SIGCHLD SIGCLD +#endif + +#ifdef SIGCHLD + RETSIGTYPE (*chfunc)(int); + + rb_last_status_clear(); + chfunc = signal(SIGCHLD, SIG_DFL); +#endif execarg_obj = rb_execarg_new(argc, argv, TRUE, TRUE); pid = rb_execarg_spawn(execarg_obj, NULL, 0); #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV) @@ -4310,6 +4106,9 @@ rb_f_system(int argc, VALUE *argv) rb_sys_fail("Another thread waited the process started by system()."); } #endif +#ifdef SIGCHLD + signal(SIGCHLD, chfunc); +#endif TypedData_Get_Struct(execarg_obj, struct rb_execarg, &exec_arg_data_type, eargp); if (pid < 0) { if (eargp->exception) { |