summaryrefslogtreecommitdiff
path: root/process.c
diff options
context:
space:
mode:
authorStan Hu <stanhu@gmail.com>2024-05-17 17:05:48 +0900
committernagachika <nagachika@ruby-lang.org>2024-08-18 18:02:09 +0900
commit65fed1c3e439bc47bcf6ec884431a86cb9ebd1dc (patch)
tree236e877de69232fc2b0adc30bf959d680b8eac46 /process.c
parent50399eebd96c76ce808ea4d84fe39693f585a531 (diff)
Allow waitpid(-1, Process::WNOHANG) to be woken if a waitpid(pid) is
...pending If two threads are running, with one calling waitpid(-1, Process::WNOHANG), and another calling waitpid($some_pid), and then $some_other_pid exits, we would expect the waitpid(-1, Process::WNOHANG) call to retrieve that exit status. However, it cannot actually do so until $some_pid _also_ exits. This patch fixes the issue by calling do_waitpid unconditionally in waitpid_wait; this will ensure that a waitpid -1 actually reaps something (after first checking that no PID-directed call wants the process). [Bug #20490]
Diffstat (limited to 'process.c')
-rw-r--r--process.c24
1 files changed, 16 insertions, 8 deletions
diff --git a/process.c b/process.c
index e8dcb82e50..c317a4cc2c 100644
--- a/process.c
+++ b/process.c
@@ -1270,6 +1270,7 @@ waitpid_cleanup(VALUE x)
return Qfalse;
}
+#if RUBY_SIGCHLD
static void
waitpid_wait(struct waitpid_state *w)
{
@@ -1283,10 +1284,17 @@ waitpid_wait(struct waitpid_state *w)
*/
rb_native_mutex_lock(&vm->waitpid_lock);
- if (w->pid > 0 || ccan_list_empty(&vm->waiting_pids)) {
- w->ret = do_waitpid(w->pid, &w->status, w->options | WNOHANG);
+ if (w->options & WNOHANG && w->pid <= 0) {
+ /* In the case of WNOHANG wait for a group, make sure there isn't a zombie child
+ * whose PID we are directly waiting for in another call to waitpid. If there is,
+ * we will reap it via a call to waitpid($pid) with this call to waitpid_each. */
+ waitpid_each(vm, &vm->waiting_pids);
+ /* _now_ it's safe to call do_waitpid, without risk of stealing the wait from
+ * another directed call. */
}
+ w->ret = do_waitpid(w->pid, &w->status, w->options | WNOHANG);
+
if (w->ret) {
if (w->ret == -1) w->errnum = errno;
}
@@ -1308,6 +1316,7 @@ waitpid_wait(struct waitpid_state *w)
rb_ensure(waitpid_sleep, (VALUE)w, waitpid_cleanup, (VALUE)w);
}
}
+#endif
static void *
waitpid_blocking_no_SIGCHLD(void *x)
@@ -1350,12 +1359,11 @@ rb_process_status_wait(rb_pid_t pid, int flags)
waitpid_state_init(&waitpid_state, pid, flags);
waitpid_state.ec = GET_EC();
- if (WAITPID_USE_SIGCHLD) {
- waitpid_wait(&waitpid_state);
- }
- else {
- waitpid_no_SIGCHLD(&waitpid_state);
- }
+#if WAITPID_USE_SIGCHLD
+ waitpid_wait(&waitpid_state);
+#else
+ waitpid_no_SIGCHLD(&waitpid_state);
+#endif
if (waitpid_state.ret == 0) return Qnil;