summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2026-02-04 13:12:42 +0100
committerHiroshi SHIBATA <hsbt@ruby-lang.org>2026-02-05 15:48:56 +0900
commit91f0a5a11006d7d6ba72c4d9128ae909c3adaaf8 (patch)
tree8810e0f1258b6435f8a556e77c4f08ec3032151d
parentd8c21d0780e0fc061a396e66d25b7b87de3108a4 (diff)
[3.3] Fix deadlock on th->interrupt_lock after fork
[Bug #21860] If a thread was holding this lock before fork, it will not exist in the child process. We should re-initialize these locks as we do with the VM locks when forking. Co-Authored-By: John Hawthorn <john@hawthorn.email> Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
-rw-r--r--bootstraptest/test_fork.rb9
-rw-r--r--thread.c1
-rw-r--r--thread_pthread.c5
3 files changed, 13 insertions, 2 deletions
diff --git a/bootstraptest/test_fork.rb b/bootstraptest/test_fork.rb
index 0cdfb5ab24..7a613026ad 100644
--- a/bootstraptest/test_fork.rb
+++ b/bootstraptest/test_fork.rb
@@ -88,14 +88,19 @@ assert_equal 'ok', %q{
10.times do
pid = fork{ exit!(0) }
- deadline = now + 1
- until Process.waitpid(pid, Process::WNOHANG)
+ deadline = now + 10
+ while true
+ _, status = Process.waitpid2(pid, Process::WNOHANG)
+ break if status
if now > deadline
Process.kill(:KILL, pid)
raise "failed"
end
sleep 0.001
end
+ unless status.success?
+ raise "child exited with status #{status}"
+ end
rescue NotImplementedError
end
:ok
diff --git a/thread.c b/thread.c
index 1fe1e01595..b2b5177d4e 100644
--- a/thread.c
+++ b/thread.c
@@ -4698,6 +4698,7 @@ static void
terminate_atfork_i(rb_thread_t *th, const rb_thread_t *current_th)
{
if (th != current_th) {
+ rb_native_mutex_initialize(&th->interrupt_lock);
rb_mutex_abandon_keeping_mutexes(th);
rb_mutex_abandon_locking_mutex(th);
thread_cleanup_func(th, TRUE);
diff --git a/thread_pthread.c b/thread_pthread.c
index ed624416aa..77994796f1 100644
--- a/thread_pthread.c
+++ b/thread_pthread.c
@@ -1531,6 +1531,11 @@ thread_sched_atfork(struct rb_thread_sched *sched)
vm->ractor.sched.running_cnt = 0;
rb_native_mutex_initialize(&vm->ractor.sched.lock);
+#if VM_CHECK_MODE > 0
+ vm->ractor.sched.lock_owner = NULL;
+ vm->ractor.sched.locked = false;
+#endif
+
// rb_native_cond_destroy(&vm->ractor.sched.cond);
rb_native_cond_initialize(&vm->ractor.sched.cond);
rb_native_cond_initialize(&vm->ractor.sched.barrier_complete_cond);