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]
This commit is contained in:
parent
075a102c93
commit
aa63699d10
Notes:
git
2024-11-08 09:03:09 +00:00
@ -211,17 +211,6 @@ assert_equal '[:a, :b, :c, :d, :e, :f, :g]', %q{
|
|||||||
Ractor.make_shareable(closure).call
|
Ractor.make_shareable(closure).call
|
||||||
}
|
}
|
||||||
|
|
||||||
# Now autoload in non-main Ractor is not supported
|
|
||||||
assert_equal 'ok', %q{
|
|
||||||
autoload :Foo, 'foo.rb'
|
|
||||||
r = Ractor.new do
|
|
||||||
p Foo
|
|
||||||
rescue Ractor::UnsafeError
|
|
||||||
:ok
|
|
||||||
end
|
|
||||||
r.take
|
|
||||||
}
|
|
||||||
|
|
||||||
###
|
###
|
||||||
###
|
###
|
||||||
# Ractor still has several memory corruption so skip huge number of tests
|
# Ractor still has several memory corruption so skip huge number of tests
|
||||||
@ -1836,3 +1825,80 @@ assert_equal 'true', %q{
|
|||||||
shareable = Ractor.make_shareable("chilled")
|
shareable = Ractor.make_shareable("chilled")
|
||||||
shareable == "chilled" && Ractor.shareable?(shareable)
|
shareable == "chilled" && Ractor.shareable?(shareable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# require in Ractor
|
||||||
|
assert_equal 'true', %q{
|
||||||
|
Module.new do
|
||||||
|
def require feature
|
||||||
|
return Ractor._require(feature) unless Ractor.main?
|
||||||
|
super
|
||||||
|
end
|
||||||
|
Object.prepend self
|
||||||
|
set_temporary_name 'Ractor#require'
|
||||||
|
end
|
||||||
|
|
||||||
|
Ractor.new{
|
||||||
|
require 'benchmark'
|
||||||
|
Benchmark.measure{}
|
||||||
|
}.take.real > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# require_relative in Ractor
|
||||||
|
assert_equal 'true', %q{
|
||||||
|
dummyfile = File.join(__dir__, "dummy#{rand}.rb")
|
||||||
|
return true if File.exist?(dummyfile)
|
||||||
|
|
||||||
|
begin
|
||||||
|
File.write dummyfile, ''
|
||||||
|
rescue Exception
|
||||||
|
# skip on any errors
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
Ractor.new dummyfile do |f|
|
||||||
|
require_relative File.basename(f)
|
||||||
|
end.take
|
||||||
|
ensure
|
||||||
|
File.unlink dummyfile
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
# require_relative in Ractor
|
||||||
|
assert_equal 'LoadError', %q{
|
||||||
|
dummyfile = File.join(__dir__, "not_existed_dummy#{rand}.rb")
|
||||||
|
return true if File.exist?(dummyfile)
|
||||||
|
|
||||||
|
Ractor.new dummyfile do |f|
|
||||||
|
begin
|
||||||
|
require_relative File.basename(f)
|
||||||
|
rescue LoadError => e
|
||||||
|
e.class
|
||||||
|
end
|
||||||
|
end.take
|
||||||
|
}
|
||||||
|
|
||||||
|
# autolaod in Ractor
|
||||||
|
assert_equal 'true', %q{
|
||||||
|
autoload :Benchmark, 'benchmark'
|
||||||
|
|
||||||
|
r = Ractor.new do
|
||||||
|
Benchmark.measure{}
|
||||||
|
end
|
||||||
|
r.take.real > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# failed in autolaod in Ractor
|
||||||
|
assert_equal 'LoadError', %q{
|
||||||
|
dummyfile = File.join(__dir__, "not_existed_dummy#{rand}.rb")
|
||||||
|
autoload :Benchmark, dummyfile
|
||||||
|
|
||||||
|
r = Ractor.new do
|
||||||
|
begin
|
||||||
|
Benchmark.measure{}
|
||||||
|
rescue LoadError => e
|
||||||
|
e.class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
r.take
|
||||||
|
}
|
||||||
|
23
load.c
23
load.c
@ -18,6 +18,7 @@
|
|||||||
#include "darray.h"
|
#include "darray.h"
|
||||||
#include "ruby/encoding.h"
|
#include "ruby/encoding.h"
|
||||||
#include "ruby/util.h"
|
#include "ruby/util.h"
|
||||||
|
#include "ractor_core.h"
|
||||||
|
|
||||||
static VALUE ruby_dln_libmap;
|
static VALUE ruby_dln_libmap;
|
||||||
|
|
||||||
@ -1383,17 +1384,25 @@ static VALUE
|
|||||||
rb_require_string_internal(VALUE fname, bool resurrect)
|
rb_require_string_internal(VALUE fname, bool resurrect)
|
||||||
{
|
{
|
||||||
rb_execution_context_t *ec = GET_EC();
|
rb_execution_context_t *ec = GET_EC();
|
||||||
int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
|
|
||||||
|
|
||||||
if (result > TAG_RETURN) {
|
// main ractor check
|
||||||
EC_JUMP_TAG(ec, result);
|
if (!rb_ractor_main_p()) {
|
||||||
}
|
|
||||||
if (result < 0) {
|
|
||||||
if (resurrect) fname = rb_str_resurrect(fname);
|
if (resurrect) fname = rb_str_resurrect(fname);
|
||||||
load_failed(fname);
|
return rb_ractor_require(fname);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
|
||||||
|
|
||||||
return RBOOL(result);
|
if (result > TAG_RETURN) {
|
||||||
|
EC_JUMP_TAG(ec, result);
|
||||||
|
}
|
||||||
|
if (result < 0) {
|
||||||
|
if (resurrect) fname = rb_str_resurrect(fname);
|
||||||
|
load_failed(fname);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RBOOL(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
|
248
ractor.c
248
ractor.c
@ -1956,6 +1956,7 @@ cancel_single_ractor_mode(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ruby_single_main_ractor = NULL;
|
ruby_single_main_ractor = NULL;
|
||||||
|
rb_funcall(rb_cRactor, rb_intern("_activated"), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -2136,6 +2137,13 @@ ractor_create(rb_execution_context_t *ec, VALUE self, VALUE loc, VALUE name, VAL
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
ractor_create_func(VALUE klass, VALUE loc, VALUE name, VALUE args, rb_block_call_func_t func)
|
||||||
|
{
|
||||||
|
VALUE block = rb_proc_new(func, Qnil);
|
||||||
|
return ractor_create(rb_current_ec_noinline(), klass, loc, name, args, block);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ractor_yield_atexit(rb_execution_context_t *ec, rb_ractor_t *cr, VALUE v, bool exc)
|
ractor_yield_atexit(rb_execution_context_t *ec, rb_ractor_t *cr, VALUE v, bool exc)
|
||||||
{
|
{
|
||||||
@ -2665,6 +2673,8 @@ Init_Ractor(void)
|
|||||||
rb_define_method(rb_cRactorMovedObject, "instance_eval", ractor_moved_missing, -1);
|
rb_define_method(rb_cRactorMovedObject, "instance_eval", ractor_moved_missing, -1);
|
||||||
rb_define_method(rb_cRactorMovedObject, "instance_exec", ractor_moved_missing, -1);
|
rb_define_method(rb_cRactorMovedObject, "instance_exec", ractor_moved_missing, -1);
|
||||||
|
|
||||||
|
// internal
|
||||||
|
|
||||||
#if USE_RACTOR_SELECTOR
|
#if USE_RACTOR_SELECTOR
|
||||||
rb_init_ractor_selector();
|
rb_init_ractor_selector();
|
||||||
#endif
|
#endif
|
||||||
@ -3869,4 +3879,242 @@ ractor_local_value_set(rb_execution_context_t *ec, VALUE self, VALUE sym, VALUE
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ractor::Channel (emulate with Ractor)
|
||||||
|
|
||||||
|
typedef rb_ractor_t rb_ractor_channel_t;
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
ractor_channel_func(RB_BLOCK_CALL_FUNC_ARGLIST(y, c))
|
||||||
|
{
|
||||||
|
rb_execution_context_t *ec = GET_EC();
|
||||||
|
rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
int state;
|
||||||
|
|
||||||
|
EC_PUSH_TAG(ec);
|
||||||
|
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
|
||||||
|
VALUE obj = ractor_receive(ec, cr);
|
||||||
|
ractor_yield(ec, cr, obj, Qfalse);
|
||||||
|
}
|
||||||
|
EC_POP_TAG();
|
||||||
|
|
||||||
|
if (state) {
|
||||||
|
// ignore the error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_ractor_channel_new(void)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
return rb_funcall(rb_const_get(rb_cRactor, rb_intern("Channel")), rb_intern("new"), 0);
|
||||||
|
#else
|
||||||
|
// class Channel
|
||||||
|
// def self.new
|
||||||
|
// Ractor.new do # func body
|
||||||
|
// while true
|
||||||
|
// obj = Ractor.receive
|
||||||
|
// Ractor.yield obj
|
||||||
|
// end
|
||||||
|
// rescue Ractor::ClosedError
|
||||||
|
// nil
|
||||||
|
// end
|
||||||
|
// end
|
||||||
|
// end
|
||||||
|
|
||||||
|
return ractor_create_func(rb_cRactor, Qnil, rb_str_new2("Ractor/channel"), rb_ary_new(), ractor_channel_func);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_ractor_channel_yield(rb_execution_context_t *ec, VALUE vch, VALUE obj)
|
||||||
|
{
|
||||||
|
VM_ASSERT(ec == rb_current_ec_noinline());
|
||||||
|
rb_ractor_channel_t *ch = RACTOR_PTR(vch);
|
||||||
|
|
||||||
|
ractor_send(ec, (rb_ractor_t *)ch, obj, Qfalse);
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_ractor_channel_take(rb_execution_context_t *ec, VALUE vch)
|
||||||
|
{
|
||||||
|
VM_ASSERT(ec == rb_current_ec_noinline());
|
||||||
|
rb_ractor_channel_t *ch = RACTOR_PTR(vch);
|
||||||
|
|
||||||
|
return ractor_take(ec, (rb_ractor_t *)ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_ractor_channel_close(rb_execution_context_t *ec, VALUE vch)
|
||||||
|
{
|
||||||
|
VM_ASSERT(ec == rb_current_ec_noinline());
|
||||||
|
rb_ractor_channel_t *ch = RACTOR_PTR(vch);
|
||||||
|
|
||||||
|
ractor_close_incoming(ec, (rb_ractor_t *)ch);
|
||||||
|
return ractor_close_outgoing(ec, (rb_ractor_t *)ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ractor#require
|
||||||
|
|
||||||
|
struct cross_ractor_require {
|
||||||
|
VALUE ch;
|
||||||
|
VALUE result;
|
||||||
|
VALUE exception;
|
||||||
|
|
||||||
|
// require
|
||||||
|
VALUE feature;
|
||||||
|
|
||||||
|
// autoload
|
||||||
|
VALUE module;
|
||||||
|
ID name;
|
||||||
|
};
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
require_body(VALUE data)
|
||||||
|
{
|
||||||
|
struct cross_ractor_require *crr = (struct cross_ractor_require *)data;
|
||||||
|
|
||||||
|
ID require;
|
||||||
|
CONST_ID(require, "require");
|
||||||
|
crr->result = rb_funcallv(Qnil, require, 1, &crr->feature);
|
||||||
|
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
require_rescue(VALUE data, VALUE errinfo)
|
||||||
|
{
|
||||||
|
struct cross_ractor_require *crr = (struct cross_ractor_require *)data;
|
||||||
|
crr->exception = errinfo;
|
||||||
|
return Qundef;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
require_result_copy_body(VALUE data)
|
||||||
|
{
|
||||||
|
struct cross_ractor_require *crr = (struct cross_ractor_require *)data;
|
||||||
|
|
||||||
|
if (crr->exception != Qundef) {
|
||||||
|
VM_ASSERT(crr->result == Qundef);
|
||||||
|
crr->exception = ractor_copy(crr->exception);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
VM_ASSERT(crr->result != Qundef);
|
||||||
|
crr->result = ractor_copy(crr->result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
require_result_copy_resuce(VALUE data, VALUE errinfo)
|
||||||
|
{
|
||||||
|
struct cross_ractor_require *crr = (struct cross_ractor_require *)data;
|
||||||
|
crr->exception = errinfo; // ractor_move(crr->exception);
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
ractor_require_protect(struct cross_ractor_require *crr, VALUE (*func)(VALUE))
|
||||||
|
{
|
||||||
|
// catch any error
|
||||||
|
rb_rescue2(func, (VALUE)crr,
|
||||||
|
require_rescue, (VALUE)crr, rb_eException, 0);
|
||||||
|
|
||||||
|
rb_rescue2(require_result_copy_body, (VALUE)crr,
|
||||||
|
require_result_copy_resuce, (VALUE)crr, rb_eException, 0);
|
||||||
|
|
||||||
|
rb_ractor_channel_yield(GET_EC(), crr->ch, Qtrue);
|
||||||
|
return Qnil;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
ractore_require_func(void *data)
|
||||||
|
{
|
||||||
|
struct cross_ractor_require *crr = (struct cross_ractor_require *)data;
|
||||||
|
return ractor_require_protect(crr, require_body);
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_ractor_require(VALUE feature)
|
||||||
|
{
|
||||||
|
// TODO: make feature shareable
|
||||||
|
struct cross_ractor_require crr = {
|
||||||
|
.feature = feature, // TODO: ractor
|
||||||
|
.ch = rb_ractor_channel_new(),
|
||||||
|
.result = Qundef,
|
||||||
|
.exception = Qundef,
|
||||||
|
};
|
||||||
|
|
||||||
|
rb_execution_context_t *ec = GET_EC();
|
||||||
|
rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
|
||||||
|
rb_ractor_interrupt_exec(main_r, ractore_require_func, &crr, 0);
|
||||||
|
|
||||||
|
// wait for require done
|
||||||
|
rb_ractor_channel_take(ec, crr.ch);
|
||||||
|
rb_ractor_channel_close(ec, crr.ch);
|
||||||
|
|
||||||
|
if (crr.exception != Qundef) {
|
||||||
|
rb_exc_raise(crr.exception);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return crr.result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
ractor_require(rb_execution_context_t *ec, VALUE self, VALUE feature)
|
||||||
|
{
|
||||||
|
return rb_ractor_require(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
autoload_load_body(VALUE data)
|
||||||
|
{
|
||||||
|
struct cross_ractor_require *crr = (struct cross_ractor_require *)data;
|
||||||
|
crr->result = rb_autoload_load(crr->module, crr->name);
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
ractor_autoload_load_func(void *data)
|
||||||
|
{
|
||||||
|
struct cross_ractor_require *crr = (struct cross_ractor_require *)data;
|
||||||
|
return ractor_require_protect(crr, autoload_load_body);
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_ractor_autoload_load(VALUE module, ID name)
|
||||||
|
{
|
||||||
|
struct cross_ractor_require crr = {
|
||||||
|
.module = module,
|
||||||
|
.name = name,
|
||||||
|
.ch = rb_ractor_channel_new(),
|
||||||
|
.result = Qundef,
|
||||||
|
.exception = Qundef,
|
||||||
|
};
|
||||||
|
|
||||||
|
rb_execution_context_t *ec = GET_EC();
|
||||||
|
rb_ractor_t *main_r = GET_VM()->ractor.main_ractor;
|
||||||
|
rb_ractor_interrupt_exec(main_r, ractor_autoload_load_func, &crr, 0);
|
||||||
|
|
||||||
|
// wait for require done
|
||||||
|
rb_ractor_channel_take(ec, crr.ch);
|
||||||
|
rb_ractor_channel_close(ec, crr.ch);
|
||||||
|
|
||||||
|
if (crr.exception != Qundef) {
|
||||||
|
rb_exc_raise(crr.exception);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return crr.result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#include "ractor.rbinc"
|
#include "ractor.rbinc"
|
||||||
|
30
ractor.rb
30
ractor.rb
@ -835,11 +835,13 @@ class Ractor
|
|||||||
end
|
end
|
||||||
|
|
||||||
# get a value from ractor-local storage of current Ractor
|
# get a value from ractor-local storage of current Ractor
|
||||||
|
# Obsolete and use Ractor.[] instead.
|
||||||
def [](sym)
|
def [](sym)
|
||||||
Primitive.ractor_local_value(sym)
|
Primitive.ractor_local_value(sym)
|
||||||
end
|
end
|
||||||
|
|
||||||
# set a value in ractor-local storage of current Ractor
|
# set a value in ractor-local storage of current Ractor
|
||||||
|
# Obsolete and use Ractor.[]= instead.
|
||||||
def []=(sym, val)
|
def []=(sym, val)
|
||||||
Primitive.ractor_local_value_set(sym, val)
|
Primitive.ractor_local_value_set(sym, val)
|
||||||
end
|
end
|
||||||
@ -867,4 +869,32 @@ class Ractor
|
|||||||
GET_VM()->ractor.main_ractor == rb_ec_ractor_ptr(ec)
|
GET_VM()->ractor.main_ractor == rb_ec_ractor_ptr(ec)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# internal method
|
||||||
|
def self._require feature
|
||||||
|
if main?
|
||||||
|
super feature
|
||||||
|
else
|
||||||
|
Primitive.ractor_require feature
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class << self
|
||||||
|
private
|
||||||
|
|
||||||
|
# internal method that is called when the first "Ractor.new" is called
|
||||||
|
def _activated
|
||||||
|
Kernel.prepend Module.new{|m|
|
||||||
|
m.set_temporary_name '<RactorRequire>'
|
||||||
|
|
||||||
|
def require feature
|
||||||
|
if Ractor.main?
|
||||||
|
super
|
||||||
|
else
|
||||||
|
Ractor._require feature
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -222,6 +222,8 @@ void rb_ractor_terminate_interrupt_main_thread(rb_ractor_t *r);
|
|||||||
void rb_ractor_terminate_all(void);
|
void rb_ractor_terminate_all(void);
|
||||||
bool rb_ractor_main_p_(void);
|
bool rb_ractor_main_p_(void);
|
||||||
void rb_ractor_atfork(rb_vm_t *vm, rb_thread_t *th);
|
void rb_ractor_atfork(rb_vm_t *vm, rb_thread_t *th);
|
||||||
|
VALUE rb_ractor_require(VALUE feature);
|
||||||
|
VALUE rb_ractor_autoload_load(VALUE space, ID id);
|
||||||
|
|
||||||
VALUE rb_ractor_ensure_shareable(VALUE obj, VALUE name);
|
VALUE rb_ractor_ensure_shareable(VALUE obj, VALUE name);
|
||||||
|
|
||||||
|
@ -845,7 +845,7 @@ thread_sched_wait_running_turn(struct rb_thread_sched *sched, rb_thread_t *th, b
|
|||||||
RUBY_DEBUG_LOG("th:%u", rb_th_serial(th));
|
RUBY_DEBUG_LOG("th:%u", rb_th_serial(th));
|
||||||
|
|
||||||
ASSERT_thread_sched_locked(sched, th);
|
ASSERT_thread_sched_locked(sched, th);
|
||||||
VM_ASSERT(th == GET_THREAD());
|
VM_ASSERT(th == rb_ec_thread_ptr(rb_current_ec_noinline()));
|
||||||
|
|
||||||
if (th != sched->running) {
|
if (th != sched->running) {
|
||||||
// already deleted from running threads
|
// already deleted from running threads
|
||||||
@ -900,12 +900,12 @@ thread_sched_wait_running_turn(struct rb_thread_sched *sched, rb_thread_t *th, b
|
|||||||
thread_sched_set_lock_owner(sched, th);
|
thread_sched_set_lock_owner(sched, th);
|
||||||
}
|
}
|
||||||
|
|
||||||
VM_ASSERT(GET_EC() == th->ec);
|
VM_ASSERT(rb_current_ec_noinline() == th->ec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VM_ASSERT(th->nt != NULL);
|
VM_ASSERT(th->nt != NULL);
|
||||||
VM_ASSERT(GET_EC() == th->ec);
|
VM_ASSERT(rb_current_ec_noinline() == th->ec);
|
||||||
VM_ASSERT(th->sched.waiting_reason.flags == thread_sched_waiting_none);
|
VM_ASSERT(th->sched.waiting_reason.flags == thread_sched_waiting_none);
|
||||||
|
|
||||||
// add th to running threads
|
// add th to running threads
|
||||||
|
@ -132,7 +132,6 @@ struct rb_thread_sched {
|
|||||||
|
|
||||||
#ifdef RB_THREAD_LOCAL_SPECIFIER
|
#ifdef RB_THREAD_LOCAL_SPECIFIER
|
||||||
NOINLINE(void rb_current_ec_set(struct rb_execution_context_struct *));
|
NOINLINE(void rb_current_ec_set(struct rb_execution_context_struct *));
|
||||||
NOINLINE(struct rb_execution_context_struct *rb_current_ec_noinline(void));
|
|
||||||
|
|
||||||
# ifdef __APPLE__
|
# ifdef __APPLE__
|
||||||
// on Darwin, TLS can not be accessed across .so
|
// on Darwin, TLS can not be accessed across .so
|
||||||
|
@ -2994,7 +2994,7 @@ rb_autoload_load(VALUE module, ID name)
|
|||||||
|
|
||||||
// At this point, we assume there might be autoloading, so fail if it's ractor:
|
// At this point, we assume there might be autoloading, so fail if it's ractor:
|
||||||
if (UNLIKELY(!rb_ractor_main_p())) {
|
if (UNLIKELY(!rb_ractor_main_p())) {
|
||||||
rb_raise(rb_eRactorUnsafeError, "require by autoload on non-main Ractor is not supported (%s)", rb_id2name(name));
|
return rb_ractor_autoload_load(module, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This state is stored on the stack and is used during the autoload process.
|
// This state is stored on the stack and is used during the autoload process.
|
||||||
|
10
vm.c
10
vm.c
@ -556,7 +556,7 @@ RB_THREAD_LOCAL_SPECIFIER rb_execution_context_t *ruby_current_ec;
|
|||||||
RB_THREAD_LOCAL_SPECIFIER rb_atomic_t ruby_nt_serial;
|
RB_THREAD_LOCAL_SPECIFIER rb_atomic_t ruby_nt_serial;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// no-inline decl on thread_pthread.h
|
// no-inline decl on vm_core.h
|
||||||
rb_execution_context_t *
|
rb_execution_context_t *
|
||||||
rb_current_ec_noinline(void)
|
rb_current_ec_noinline(void)
|
||||||
{
|
{
|
||||||
@ -580,6 +580,14 @@ rb_current_ec(void)
|
|||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
native_tls_key_t ruby_current_ec_key;
|
native_tls_key_t ruby_current_ec_key;
|
||||||
|
|
||||||
|
// no-inline decl on vm_core.h
|
||||||
|
rb_execution_context_t *
|
||||||
|
rb_current_ec_noinline(void)
|
||||||
|
{
|
||||||
|
return native_tls_get(ruby_current_ec_key);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
rb_event_flag_t ruby_vm_event_flags;
|
rb_event_flag_t ruby_vm_event_flags;
|
||||||
|
@ -1969,6 +1969,8 @@ rb_ec_vm_ptr(const rb_execution_context_t *ec)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NOINLINE(struct rb_execution_context_struct *rb_current_ec_noinline(void));
|
||||||
|
|
||||||
static inline rb_execution_context_t *
|
static inline rb_execution_context_t *
|
||||||
rb_current_execution_context(bool expect_ec)
|
rb_current_execution_context(bool expect_ec)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user