diff options
author | Sutou Kouhei <kou@clear-code.com> | 2021-08-24 11:22:00 +0900 |
---|---|---|
committer | Sutou Kouhei <kou@cozmixng.org> | 2021-08-26 13:29:58 +0900 |
commit | a2ad0cb7b44a0cb87bd552b312a70bc46016a95f (patch) | |
tree | dc7f82a90e6a9b0649f31a935dfdcac68f49ae17 /hash.c | |
parent | 27410eaeb2482b6a2e3e60e566dc0d892d3b2e16 (diff) |
Make Hash#each family usable in Ractor
We don't need to increment/decrement iteration level for frozen Hash
because frozen Hash can't be modified. We can assume that nobody
changes the target Hash while calling #each family.
How to reproduce:
a = {}
100.times do |i|
a[i] = true
end
Ractor.make_shareable(a)
4.times.collect do
Ractor.new(a) do |b|
100.times do
b.each_value do
end
end
end
end.each(&:take)
Example output:
internal:ractor>:267: warning: Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues.
#<Thread:0x00007fcfb087bb30 run> terminated with exception (report_on_exception is true):
#<Thread:0x00007fcfb087b8d8 run> terminated with exception (report_on_exception is true):
#<Thread:0x00007fcfb088d678 run> terminated with exception (report_on_exception is true):
#<Thread:0x00007fcfb087bd88 run> terminated with exception (report_on_exception is true):
/tmp/h.rb:10:in `each_value'/tmp/h.rb:10:in `each_value': : /tmp/h.rb:10:in `each_value'no implicit conversion from nil to integer/tmp/h.rb:10:in `each_value'no implicit conversion from nil to integer (: : (TypeErrorTypeError)no implicit conversion from nil to integer)no implicit conversion from nil to integer (
(TypeErrorTypeError from /tmp/h.rb:10:in `block (3 levels) in <main>'
from /tmp/h.rb:10:in `block (3 levels) in <main>'
)) from /tmp/h.rb:9:in `times'
from /tmp/h.rb:9:in `times'
from /tmp/h.rb:9:in `block (2 levels) in <main>'
from /tmp/h.rb:10:in `block (3 levels) in <main>'
from /tmp/h.rb:10:in `block (3 levels) in <main>'
from /tmp/h.rb:9:in `block (2 levels) in <main>'
from /tmp/h.rb:9:in `times'
from /tmp/h.rb:9:in `times'
from /tmp/h.rb:9:in `block (2 levels) in <main>'
from /tmp/h.rb:9:in `block (2 levels) in <main>'
<internal:ractor>:694:in `take': thrown by remote Ractor. (Ractor::RemoteError)
from /tmp/h.rb:14:in `each'
from /tmp/h.rb:14:in `<main>'
/tmp/h.rb:10:in `each_value': no implicit conversion from nil to integer (TypeError)
from /tmp/h.rb:10:in `block (3 levels) in <main>'
from /tmp/h.rb:9:in `times'
from /tmp/h.rb:9:in `block (2 levels) in <main>'
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/4768
Diffstat (limited to 'hash.c')
-rw-r--r-- | hash.c | 9 |
1 files changed, 7 insertions, 2 deletions
@@ -1503,11 +1503,16 @@ rb_hash_foreach(VALUE hash, rb_foreach_func *func, VALUE farg) if (RHASH_TABLE_EMPTY_P(hash)) return; - hash_iter_lev_inc(hash); arg.hash = hash; arg.func = (rb_foreach_func *)func; arg.arg = farg; - rb_ensure(hash_foreach_call, (VALUE)&arg, hash_foreach_ensure, hash); + if (RB_OBJ_FROZEN(hash)) { + hash_foreach_call((VALUE)&arg); + } + else { + hash_iter_lev_inc(hash); + rb_ensure(hash_foreach_call, (VALUE)&arg, hash_foreach_ensure, hash); + } hash_verify(hash); } |