summaryrefslogtreecommitdiff
path: root/ractor.c
diff options
context:
space:
mode:
authorAlan Wu <XrXr@users.noreply.github.com>2022-03-28 17:00:45 -0400
committerGitHub <noreply@github.com>2022-03-28 17:00:45 -0400
commit51e98eab1f2d43f3d77f6e148b2bd07709379b8f (patch)
tree05ed055df63b54a9215942cb33c1ea7ae960e1a4 /ractor.c
parent5525e47a0b5e6b6c3e13ceec4b44535feba22631 (diff)
downloadruby-51e98eab1f2d43f3d77f6e148b2bd07709379b8f.tar.gz
Fix Ractor.receive_if + rb_vm_barrier() deadlock
I have this scripts that deadlocks after about 5 minutes if I repeatedly run it with a shell loop: ```ruby $VERBOSE = nil lamb = ->(main, gc) do gc.verify_internal_consistency gc.verify_internal_consistency main << 1 gc.verify_internal_consistency gc.verify_internal_consistency main << 2 gc.verify_internal_consistency gc.verify_internal_consistency main << 3 gc.verify_internal_consistency gc.verify_internal_consistency end lamb[[], GC] lamb[[], GC] r = Ractor.new Ractor.current, GC, &lamb a = [] a << Ractor.receive_if{|msg| msg == 2} a << Ractor.receive_if{|msg| msg == 3} a << Ractor.receive_if{|msg| msg == 1} ``` Shell loop: ```shell while ./miniruby deadlock.rb; do date; done ``` Once it locks up, CTRL-C doesn't interrupt the process which led me to infer `receive_if` is looping in `ractor_receive_if()` without checking for interrupts. This can be confirmed by attaching a debugger to the deadlocked miniruby. The deadlock has one thread looping in `receive_if` and another waiting in `rb_vm_barrier()`. The barrier relies on interrupt checking to finish. Theoretically speaking the `rb_vm_barrier()` could come from one thread naturally starting GC. We found this while developing YJIT but it dead locks running with YJIT disabled. YJIT currently relies on `rb_vm_barrier()` to synchronize before changing memory protection. This diff adds an interrupt check in the loop in `Ractor#receive_if` which seems to fix the deadlock. In addition, this commit allows interrupting the following single ractor script with CTRL-C. ```shell ruby -e 'Ractor.current.send(3); Ractor.receive_if { false }' ```
Diffstat (limited to 'ractor.c')
-rw-r--r--ractor.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/ractor.c b/ractor.c
index d6559dfc2a..ccdfd32710 100644
--- a/ractor.c
+++ b/ractor.c
@@ -886,6 +886,8 @@ ractor_receive_if(rb_execution_context_t *ec, VALUE crv, VALUE b)
if (result != Qundef) return result;
index++;
}
+
+ RUBY_VM_CHECK_INTS(ec);
}
}