Skip to content

Commit aa63699

Browse files
committed
support require in non-main Ractors
Many libraries should be loaded on the main ractor because of setting constants with unshareable objects and so on. This patch allows to call `requore` on non-main Ractors by asking the main ractor to call `require` on it. The calling ractor waits for the result of `require` from the main ractor. If the `require` call failed with some reasons, an exception objects will be deliverred from the main ractor to the calling ractor if it is copy-able. Same on `require_relative` and `require` by `autoload`. Now `Ractor.new{pp obj}` works well (the first call of `pp` requires `pp` library implicitly). [Feature #20627]
1 parent 075a102 commit aa63699

File tree

10 files changed

+388
-24
lines changed

10 files changed

+388
-24
lines changed

bootstraptest/test_ractor.rb

Lines changed: 77 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -211,17 +211,6 @@
211211
Ractor.make_shareable(closure).call
212212
}
213213

214-
# Now autoload in non-main Ractor is not supported
215-
assert_equal 'ok', %q{
216-
autoload :Foo, 'foo.rb'
217-
r = Ractor.new do
218-
p Foo
219-
rescue Ractor::UnsafeError
220-
:ok
221-
end
222-
r.take
223-
}
224-
225214
###
226215
###
227216
# Ractor still has several memory corruption so skip huge number of tests
@@ -1836,3 +1825,80 @@ class C8; def self.foo = 17; end
18361825
shareable = Ractor.make_shareable("chilled")
18371826
shareable == "chilled" && Ractor.shareable?(shareable)
18381827
}
1828+
1829+
# require in Ractor
1830+
assert_equal 'true', %q{
1831+
Module.new do
1832+
def require feature
1833+
return Ractor._require(feature) unless Ractor.main?
1834+
super
1835+
end
1836+
Object.prepend self
1837+
set_temporary_name 'Ractor#require'
1838+
end
1839+
1840+
Ractor.new{
1841+
require 'benchmark'
1842+
Benchmark.measure{}
1843+
}.take.real > 0
1844+
}
1845+
1846+
# require_relative in Ractor
1847+
assert_equal 'true', %q{
1848+
dummyfile = File.join(__dir__, "dummy#{rand}.rb")
1849+
return true if File.exist?(dummyfile)
1850+
1851+
begin
1852+
File.write dummyfile, ''
1853+
rescue Exception
1854+
# skip on any errors
1855+
return true
1856+
end
1857+
1858+
begin
1859+
Ractor.new dummyfile do |f|
1860+
require_relative File.basename(f)
1861+
end.take
1862+
ensure
1863+
File.unlink dummyfile
1864+
end
1865+
}
1866+
1867+
# require_relative in Ractor
1868+
assert_equal 'LoadError', %q{
1869+
dummyfile = File.join(__dir__, "not_existed_dummy#{rand}.rb")
1870+
return true if File.exist?(dummyfile)
1871+
1872+
Ractor.new dummyfile do |f|
1873+
begin
1874+
require_relative File.basename(f)
1875+
rescue LoadError => e
1876+
e.class
1877+
end
1878+
end.take
1879+
}
1880+
1881+
# autolaod in Ractor
1882+
assert_equal 'true', %q{
1883+
autoload :Benchmark, 'benchmark'
1884+
1885+
r = Ractor.new do
1886+
Benchmark.measure{}
1887+
end
1888+
r.take.real > 0
1889+
}
1890+
1891+
# failed in autolaod in Ractor
1892+
assert_equal 'LoadError', %q{
1893+
dummyfile = File.join(__dir__, "not_existed_dummy#{rand}.rb")
1894+
autoload :Benchmark, dummyfile
1895+
1896+
r = Ractor.new do
1897+
begin
1898+
Benchmark.measure{}
1899+
rescue LoadError => e
1900+
e.class
1901+
end
1902+
end
1903+
r.take
1904+
}

load.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "darray.h"
1919
#include "ruby/encoding.h"
2020
#include "ruby/util.h"
21+
#include "ractor_core.h"
2122

2223
static VALUE ruby_dln_libmap;
2324

@@ -1383,17 +1384,25 @@ static VALUE
13831384
rb_require_string_internal(VALUE fname, bool resurrect)
13841385
{
13851386
rb_execution_context_t *ec = GET_EC();
1386-
int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
13871387

1388-
if (result > TAG_RETURN) {
1389-
EC_JUMP_TAG(ec, result);
1390-
}
1391-
if (result < 0) {
1388+
// main ractor check
1389+
if (!rb_ractor_main_p()) {
13921390
if (resurrect) fname = rb_str_resurrect(fname);
1393-
load_failed(fname);
1391+
return rb_ractor_require(fname);
13941392
}
1393+
else {
1394+
int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
1395+
1396+
if (result > TAG_RETURN) {
1397+
EC_JUMP_TAG(ec, result);
1398+
}
1399+
if (result < 0) {
1400+
if (resurrect) fname = rb_str_resurrect(fname);
1401+
load_failed(fname);
1402+
}
13951403

1396-
return RBOOL(result);
1404+
return RBOOL(result);
1405+
}
13971406
}
13981407

13991408
VALUE

0 commit comments

Comments
 (0)