[前][次][番号順一覧][スレッド一覧]

ruby-changes:71535

From: Alan <ko1@a...>
Date: Tue, 29 Mar 2022 06:00:57 +0900 (JST)
Subject: [ruby-changes:71535] 51e98eab1f (master): Fix Ractor.receive_if + rb_vm_barrier() deadlock

https://git.ruby-lang.org/ruby.git/commit/?id=51e98eab1f

From 51e98eab1f2d43f3d77f6e148b2bd07709379b8f Mon Sep 17 00:00:00 2001
From: Alan Wu <XrXr@u...>
Date: Mon, 28 Mar 2022 17:00:45 -0400
Subject: 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 }'
```
---
 ractor.c | 2 ++
 1 file changed, 2 insertions(+)

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) https://github.com/ruby/ruby/blob/trunk/ractor.c#L886
             if (result != Qundef) return result;
             index++;
         }
+
+        RUBY_VM_CHECK_INTS(ec);
     }
 }
 
-- 
cgit v1.2.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]