mirror of
https://github.com/ruby/ruby.git
synced 2025-09-15 08:33:58 +02:00
Ractor: lock around global variable get/set
There's a global id_table `rb_global_tbl` that needs a lock (I used VM lock). In the future, we might use a lock-free rb_id_table if we create such a data structure. Reproduction script that might crash or behave strangely: ```ruby 100.times do Ractor.new do 1_000_000.times do $stderr $stdout $stdin $VERBOSE $stderr $stdout $stdin $VERBOSE $stderr $stdout $stdin $VERBOSE end end end $myglobal0 = nil; $myglobal1 = nil; # ... vim macros to the rescue $myglobal100000 = nil; ```
This commit is contained in:
parent
c3d91eb4d9
commit
be58cd4d7d
2 changed files with 81 additions and 70 deletions
|
@ -588,8 +588,8 @@ assert_equal 'true', %q{
|
|||
r.value[:frozen]
|
||||
}
|
||||
|
||||
# Access to global-variables are prohibited
|
||||
assert_equal 'can not access global variables $gv from non-main Ractors', %q{
|
||||
# Access to global-variables are prohibited (read)
|
||||
assert_equal 'can not access global variable $gv from non-main Ractor', %q{
|
||||
$gv = 1
|
||||
r = Ractor.new do
|
||||
$gv
|
||||
|
@ -602,8 +602,8 @@ assert_equal 'can not access global variables $gv from non-main Ractors', %q{
|
|||
end
|
||||
}
|
||||
|
||||
# Access to global-variables are prohibited
|
||||
assert_equal 'can not access global variables $gv from non-main Ractors', %q{
|
||||
# Access to global-variables are prohibited (write)
|
||||
assert_equal 'can not access global variable $gv from non-main Ractor', %q{
|
||||
r = Ractor.new do
|
||||
$gv = 1
|
||||
end
|
||||
|
|
25
variable.c
25
variable.c
|
@ -584,6 +584,7 @@ rb_find_global_entry(ID id)
|
|||
struct rb_global_entry *entry;
|
||||
VALUE data;
|
||||
|
||||
RB_VM_LOCKING() {
|
||||
if (!rb_id_table_lookup(rb_global_tbl, id, &data)) {
|
||||
entry = NULL;
|
||||
}
|
||||
|
@ -591,9 +592,10 @@ rb_find_global_entry(ID id)
|
|||
entry = (struct rb_global_entry *)data;
|
||||
RUBY_ASSERT(entry != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (UNLIKELY(!rb_ractor_main_p()) && (!entry || !entry->ractor_local)) {
|
||||
rb_raise(rb_eRactorIsolationError, "can not access global variables %s from non-main Ractors", rb_id2name(id));
|
||||
rb_raise(rb_eRactorIsolationError, "can not access global variable %s from non-main Ractor", rb_id2name(id));
|
||||
}
|
||||
|
||||
return entry;
|
||||
|
@ -621,7 +623,9 @@ rb_gvar_undef_compactor(void *var)
|
|||
static struct rb_global_entry*
|
||||
rb_global_entry(ID id)
|
||||
{
|
||||
struct rb_global_entry *entry = rb_find_global_entry(id);
|
||||
struct rb_global_entry *entry;
|
||||
RB_VM_LOCKING() {
|
||||
entry = rb_find_global_entry(id);
|
||||
if (!entry) {
|
||||
struct rb_global_variable *var;
|
||||
entry = ALLOC(struct rb_global_entry);
|
||||
|
@ -641,6 +645,7 @@ rb_global_entry(ID id)
|
|||
var->namespace_ready = false;
|
||||
rb_id_table_insert(rb_global_tbl, id, (VALUE)entry);
|
||||
}
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
@ -1003,6 +1008,7 @@ rb_gvar_set(ID id, VALUE val)
|
|||
struct rb_global_entry *entry;
|
||||
const rb_namespace_t *ns = rb_current_namespace();
|
||||
|
||||
RB_VM_LOCKING() {
|
||||
entry = rb_global_entry(id);
|
||||
|
||||
if (USE_NAMESPACE_GVAR_TBL(ns, entry)) {
|
||||
|
@ -1013,6 +1019,7 @@ rb_gvar_set(ID id, VALUE val)
|
|||
else {
|
||||
retval = rb_gvar_set_entry(entry, val);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -1026,9 +1033,11 @@ VALUE
|
|||
rb_gvar_get(ID id)
|
||||
{
|
||||
VALUE retval, gvars, key;
|
||||
const rb_namespace_t *ns = rb_current_namespace();
|
||||
// TODO: use lock-free rb_id_table when it's available for use (doesn't yet exist)
|
||||
RB_VM_LOCKING() {
|
||||
struct rb_global_entry *entry = rb_global_entry(id);
|
||||
struct rb_global_variable *var = entry->var;
|
||||
const rb_namespace_t *ns = rb_current_namespace();
|
||||
|
||||
if (USE_NAMESPACE_GVAR_TBL(ns, entry)) {
|
||||
gvars = ns->gvar_tbl;
|
||||
|
@ -1047,6 +1056,7 @@ rb_gvar_get(ID id)
|
|||
else {
|
||||
retval = (*var->getter)(entry->id, var->data);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -1128,7 +1138,7 @@ rb_f_global_variables(void)
|
|||
void
|
||||
rb_alias_variable(ID name1, ID name2)
|
||||
{
|
||||
struct rb_global_entry *entry1, *entry2;
|
||||
struct rb_global_entry *entry1 = NULL, *entry2;
|
||||
VALUE data1;
|
||||
struct rb_id_table *gtbl = rb_global_tbl;
|
||||
|
||||
|
@ -1136,6 +1146,7 @@ rb_alias_variable(ID name1, ID name2)
|
|||
rb_raise(rb_eRactorIsolationError, "can not access global variables from non-main Ractors");
|
||||
}
|
||||
|
||||
RB_VM_LOCKING() {
|
||||
entry2 = rb_global_entry(name2);
|
||||
if (!rb_id_table_lookup(gtbl, name1, &data1)) {
|
||||
entry1 = ALLOC(struct rb_global_entry);
|
||||
|
@ -1152,12 +1163,12 @@ rb_alias_variable(ID name1, ID name2)
|
|||
free_global_variable(var);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
if (entry1) {
|
||||
entry2->var->counter++;
|
||||
entry1->var = entry2->var;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(ID id)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue