[#108552] [Ruby master Bug#18782] Race conditions in autoload when loading the same feature with multiple threads. — "ioquatix (Samuel Williams)" <noreply@...>
Issue #18782 has been reported by ioquatix (Samuel Williams).
11 messages
2022/05/14
[ruby-core:108478] [Ruby master Bug#18663] Autoload doesn't work with fiber context switch.
From:
"ioquatix (Samuel Williams)" <noreply@...>
Date:
2022-05-07 05:41:37 UTC
List:
ruby-core #108478
Issue #18663 has been updated by ioquatix (Samuel Williams).
https://github.com/ruby/ruby/pull/5788 fixes this issue.
I've confirmed that my PR fixes the given examples here.
There is a tiny bit of extra overhead; using a mutex has an object allocation, mutex lock and unlock, etc.
A light weight concurrency construct `rb_condition` or `rb_fiber_condition` that behaves like a "pessimistic mutex", i.e. avoids the allocation until it's actually needed might be a better solution but let's get it correct first, and we can optimise it later.
Just a few notes:
```c
struct rb_condition {
... waitq;
}
VALUE rb_condition_wait(struct rb_condition *condition, VALUE timeout);
rb_condition_signal(struct rb_condition *condition, VALUE result); // wake up all waiters
```
----------------------------------------
Bug #18663: Autoload doesn't work with fiber context switch.
https://bugs.ruby-lang.org/issues/18663#change-97521
* Author: ioquatix (Samuel Williams)
* Status: Open
* Priority: Normal
* Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
As discussed most recently here: https://github.com/ruby/debug/issues/580
The following program appears to work:
```ruby
#!/usr/bin/env ruby
require 'tempfile'
Tempfile.create(['foo', '.rb']) do |file|
file.write(<<~RUBY)
#
$stderr.puts 1; q = Queue.new
$stderr.puts 2; t = Thread.new{q.pop}
$stderr.puts 3; q << :sig
$stderr.puts 4; t.join
sleep 1
class C
end
RUBY
file.close
autoload :C, file.path
Thread.new do
threads = 3.times.map do |i|
Thread.new do
$stderr.puts "LOADING C"
$stderr.puts C
end
end
threads.each(&:join)
end.join
end
```
This one doesn't:
```ruby
#!/usr/bin/env ruby
require 'tempfile'
require_relative 'lib/async'
Tempfile.create(['foo', '.rb']) do |file|
file.write(<<~RUBY)
#
$stderr.puts 1; q = Queue.new
$stderr.puts 2; t = Thread.new{q.pop}
$stderr.puts 3; q << :sig
$stderr.puts 4; t.join
class C
end
RUBY
file.close
autoload :C, file.path
Async do |task|
3.times do |i|
task.async do
$stderr.puts "LOADING C"
$stderr.puts C
end
end
end.wait
end
```
Semantically, they should be very similar. It feels like someone is checking the current thread rather than the current fiber or there is a poor implementation of locking somewhere, however I don't actually know for sure yet, investigation is required.
--
https://bugs.ruby-lang.org/
Unsubscribe: <mailto:ruby-core-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>