mirror of
https://github.com/ruby/ruby.git
synced 2025-09-15 16:44:01 +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]
|
r.value[:frozen]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Access to global-variables are prohibited
|
# Access to global-variables are prohibited (read)
|
||||||
assert_equal 'can not access global variables $gv from non-main Ractors', %q{
|
assert_equal 'can not access global variable $gv from non-main Ractor', %q{
|
||||||
$gv = 1
|
$gv = 1
|
||||||
r = Ractor.new do
|
r = Ractor.new do
|
||||||
$gv
|
$gv
|
||||||
|
@ -602,8 +602,8 @@ assert_equal 'can not access global variables $gv from non-main Ractors', %q{
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
# Access to global-variables are prohibited
|
# Access to global-variables are prohibited (write)
|
||||||
assert_equal 'can not access global variables $gv from non-main Ractors', %q{
|
assert_equal 'can not access global variable $gv from non-main Ractor', %q{
|
||||||
r = Ractor.new do
|
r = Ractor.new do
|
||||||
$gv = 1
|
$gv = 1
|
||||||
end
|
end
|
||||||
|
|
25
variable.c
25
variable.c
|
@ -584,6 +584,7 @@ rb_find_global_entry(ID id)
|
||||||
struct rb_global_entry *entry;
|
struct rb_global_entry *entry;
|
||||||
VALUE data;
|
VALUE data;
|
||||||
|
|
||||||
|
RB_VM_LOCKING() {
|
||||||
if (!rb_id_table_lookup(rb_global_tbl, id, &data)) {
|
if (!rb_id_table_lookup(rb_global_tbl, id, &data)) {
|
||||||
entry = NULL;
|
entry = NULL;
|
||||||
}
|
}
|
||||||
|
@ -591,9 +592,10 @@ rb_find_global_entry(ID id)
|
||||||
entry = (struct rb_global_entry *)data;
|
entry = (struct rb_global_entry *)data;
|
||||||
RUBY_ASSERT(entry != NULL);
|
RUBY_ASSERT(entry != NULL);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (UNLIKELY(!rb_ractor_main_p()) && (!entry || !entry->ractor_local)) {
|
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;
|
return entry;
|
||||||
|
@ -621,7 +623,9 @@ rb_gvar_undef_compactor(void *var)
|
||||||
static struct rb_global_entry*
|
static struct rb_global_entry*
|
||||||
rb_global_entry(ID id)
|
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) {
|
if (!entry) {
|
||||||
struct rb_global_variable *var;
|
struct rb_global_variable *var;
|
||||||
entry = ALLOC(struct rb_global_entry);
|
entry = ALLOC(struct rb_global_entry);
|
||||||
|
@ -641,6 +645,7 @@ rb_global_entry(ID id)
|
||||||
var->namespace_ready = false;
|
var->namespace_ready = false;
|
||||||
rb_id_table_insert(rb_global_tbl, id, (VALUE)entry);
|
rb_id_table_insert(rb_global_tbl, id, (VALUE)entry);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1003,6 +1008,7 @@ rb_gvar_set(ID id, VALUE val)
|
||||||
struct rb_global_entry *entry;
|
struct rb_global_entry *entry;
|
||||||
const rb_namespace_t *ns = rb_current_namespace();
|
const rb_namespace_t *ns = rb_current_namespace();
|
||||||
|
|
||||||
|
RB_VM_LOCKING() {
|
||||||
entry = rb_global_entry(id);
|
entry = rb_global_entry(id);
|
||||||
|
|
||||||
if (USE_NAMESPACE_GVAR_TBL(ns, entry)) {
|
if (USE_NAMESPACE_GVAR_TBL(ns, entry)) {
|
||||||
|
@ -1013,6 +1019,7 @@ rb_gvar_set(ID id, VALUE val)
|
||||||
else {
|
else {
|
||||||
retval = rb_gvar_set_entry(entry, val);
|
retval = rb_gvar_set_entry(entry, val);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1026,9 +1033,11 @@ VALUE
|
||||||
rb_gvar_get(ID id)
|
rb_gvar_get(ID id)
|
||||||
{
|
{
|
||||||
VALUE retval, gvars, key;
|
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_entry *entry = rb_global_entry(id);
|
||||||
struct rb_global_variable *var = entry->var;
|
struct rb_global_variable *var = entry->var;
|
||||||
const rb_namespace_t *ns = rb_current_namespace();
|
|
||||||
|
|
||||||
if (USE_NAMESPACE_GVAR_TBL(ns, entry)) {
|
if (USE_NAMESPACE_GVAR_TBL(ns, entry)) {
|
||||||
gvars = ns->gvar_tbl;
|
gvars = ns->gvar_tbl;
|
||||||
|
@ -1047,6 +1056,7 @@ rb_gvar_get(ID id)
|
||||||
else {
|
else {
|
||||||
retval = (*var->getter)(entry->id, var->data);
|
retval = (*var->getter)(entry->id, var->data);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1128,7 +1138,7 @@ rb_f_global_variables(void)
|
||||||
void
|
void
|
||||||
rb_alias_variable(ID name1, ID name2)
|
rb_alias_variable(ID name1, ID name2)
|
||||||
{
|
{
|
||||||
struct rb_global_entry *entry1, *entry2;
|
struct rb_global_entry *entry1 = NULL, *entry2;
|
||||||
VALUE data1;
|
VALUE data1;
|
||||||
struct rb_id_table *gtbl = rb_global_tbl;
|
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_raise(rb_eRactorIsolationError, "can not access global variables from non-main Ractors");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RB_VM_LOCKING() {
|
||||||
entry2 = rb_global_entry(name2);
|
entry2 = rb_global_entry(name2);
|
||||||
if (!rb_id_table_lookup(gtbl, name1, &data1)) {
|
if (!rb_id_table_lookup(gtbl, name1, &data1)) {
|
||||||
entry1 = ALLOC(struct rb_global_entry);
|
entry1 = ALLOC(struct rb_global_entry);
|
||||||
|
@ -1152,12 +1163,12 @@ rb_alias_variable(ID name1, ID name2)
|
||||||
free_global_variable(var);
|
free_global_variable(var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
if (entry1) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
entry2->var->counter++;
|
entry2->var->counter++;
|
||||||
entry1->var = entry2->var;
|
entry1->var = entry2->var;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(ID id)
|
IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(ID id)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue