diff options
| author | Jean Boussier <jean.boussier@gmail.com> | 2026-02-04 13:12:42 +0100 |
|---|---|---|
| committer | nagachika <nagachika@ruby-lang.org> | 2026-03-07 13:41:44 +0900 |
| commit | 43771bb0efcd139acd9112a770e8b8d719118dce (patch) | |
| tree | 23388d21d40190b392c161a42db4092de2ca6e93 | |
| parent | a93ff4880da5c4e56f7ec2066a9c3f7748892231 (diff) | |
[3.4] 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.rb | 7 | ||||
| -rw-r--r-- | thread.c | 1 | ||||
| -rw-r--r-- | thread_pthread.c | 5 |
3 files changed, 12 insertions, 1 deletions
diff --git a/bootstraptest/test_fork.rb b/bootstraptest/test_fork.rb index a54316dbca..860ef285d0 100644 --- a/bootstraptest/test_fork.rb +++ b/bootstraptest/test_fork.rb @@ -85,13 +85,18 @@ assert_equal 'ok', %q{ 10.times do pid = fork{ exit!(0) } deadline = now + 10 - until Process.waitpid(pid, Process::WNOHANG) + 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 @@ -4764,6 +4764,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 ba229a6dfd..8ba1ad48d3 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -1550,6 +1550,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); |
