зеркало из https://github.com/github/ruby.git
should not use rb_ary_modify()
ractor_copy() used rb_ary_modify() to make sure this array is not sharing anything, but it also checks frozen flag. So frozen arrays raises an error. To solve this issue, this patch introduces new function rb_ary_cancel_sharing() which makes sure the array does not share another array and it doesn't check frozen flag. [Bug #17343] A test is quoted from https://github.com/ruby/ruby/pull/3817
This commit is contained in:
Родитель
d2cfb5228a
Коммит
8247b8edde
28
array.c
28
array.c
|
@ -562,34 +562,33 @@ rb_ary_modify_check(VALUE ary)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rb_ary_modify(VALUE ary)
|
rb_ary_cancel_sharing(VALUE ary)
|
||||||
{
|
{
|
||||||
rb_ary_modify_check(ary);
|
|
||||||
if (ARY_SHARED_P(ary)) {
|
if (ARY_SHARED_P(ary)) {
|
||||||
long shared_len, len = RARRAY_LEN(ary);
|
long shared_len, len = RARRAY_LEN(ary);
|
||||||
VALUE shared_root = ARY_SHARED_ROOT(ary);
|
VALUE shared_root = ARY_SHARED_ROOT(ary);
|
||||||
|
|
||||||
ary_verify(shared_root);
|
ary_verify(shared_root);
|
||||||
|
|
||||||
if (len <= RARRAY_EMBED_LEN_MAX) {
|
if (len <= RARRAY_EMBED_LEN_MAX) {
|
||||||
const VALUE *ptr = ARY_HEAP_PTR(ary);
|
const VALUE *ptr = ARY_HEAP_PTR(ary);
|
||||||
FL_UNSET_SHARED(ary);
|
FL_UNSET_SHARED(ary);
|
||||||
FL_SET_EMBED(ary);
|
FL_SET_EMBED(ary);
|
||||||
MEMCPY((VALUE *)ARY_EMBED_PTR(ary), ptr, VALUE, len);
|
MEMCPY((VALUE *)ARY_EMBED_PTR(ary), ptr, VALUE, len);
|
||||||
rb_ary_decrement_share(shared_root);
|
rb_ary_decrement_share(shared_root);
|
||||||
ARY_SET_EMBED_LEN(ary, len);
|
ARY_SET_EMBED_LEN(ary, len);
|
||||||
}
|
}
|
||||||
else if (ARY_SHARED_ROOT_OCCUPIED(shared_root) && len > ((shared_len = RARRAY_LEN(shared_root))>>1)) {
|
else if (ARY_SHARED_ROOT_OCCUPIED(shared_root) && len > ((shared_len = RARRAY_LEN(shared_root))>>1)) {
|
||||||
long shift = RARRAY_CONST_PTR_TRANSIENT(ary) - RARRAY_CONST_PTR_TRANSIENT(shared_root);
|
long shift = RARRAY_CONST_PTR_TRANSIENT(ary) - RARRAY_CONST_PTR_TRANSIENT(shared_root);
|
||||||
FL_UNSET_SHARED(ary);
|
FL_UNSET_SHARED(ary);
|
||||||
ARY_SET_PTR(ary, RARRAY_CONST_PTR_TRANSIENT(shared_root));
|
ARY_SET_PTR(ary, RARRAY_CONST_PTR_TRANSIENT(shared_root));
|
||||||
ARY_SET_CAPA(ary, shared_len);
|
ARY_SET_CAPA(ary, shared_len);
|
||||||
RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
|
||||||
MEMMOVE(ptr, ptr+shift, VALUE, len);
|
MEMMOVE(ptr, ptr+shift, VALUE, len);
|
||||||
});
|
});
|
||||||
FL_SET_EMBED(shared_root);
|
FL_SET_EMBED(shared_root);
|
||||||
rb_ary_decrement_share(shared_root);
|
rb_ary_decrement_share(shared_root);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
VALUE *ptr = ary_heap_alloc(ary, len);
|
VALUE *ptr = ary_heap_alloc(ary, len);
|
||||||
MEMCPY(ptr, ARY_HEAP_PTR(ary), VALUE, len);
|
MEMCPY(ptr, ARY_HEAP_PTR(ary), VALUE, len);
|
||||||
|
@ -598,11 +597,18 @@ rb_ary_modify(VALUE ary)
|
||||||
ARY_SET_PTR(ary, ptr);
|
ARY_SET_PTR(ary, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
rb_gc_writebarrier_remember(ary);
|
rb_gc_writebarrier_remember(ary);
|
||||||
}
|
}
|
||||||
ary_verify(ary);
|
ary_verify(ary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_ary_modify(VALUE ary)
|
||||||
|
{
|
||||||
|
rb_ary_modify_check(ary);
|
||||||
|
rb_ary_cancel_sharing(ary);
|
||||||
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
ary_ensure_room_for_push(VALUE ary, long add_len)
|
ary_ensure_room_for_push(VALUE ary, long add_len)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1022,6 +1022,13 @@ assert_equal 'can not make a Proc shareable because it accesses outer variables
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Ractor deep copies frozen objects
|
||||||
|
assert_equal '[true, false]', %q{
|
||||||
|
Ractor.new([[]].freeze) { |ary|
|
||||||
|
[ary.frozen?, ary.first.frozen? ]
|
||||||
|
}.take
|
||||||
|
}
|
||||||
|
|
||||||
###
|
###
|
||||||
### Synchronization tests
|
### Synchronization tests
|
||||||
###
|
###
|
||||||
|
|
|
@ -29,6 +29,8 @@ VALUE rb_ary_tmp_new_fill(long capa);
|
||||||
VALUE rb_ary_at(VALUE, VALUE);
|
VALUE rb_ary_at(VALUE, VALUE);
|
||||||
size_t rb_ary_memsize(VALUE);
|
size_t rb_ary_memsize(VALUE);
|
||||||
VALUE rb_to_array_type(VALUE obj);
|
VALUE rb_to_array_type(VALUE obj);
|
||||||
|
void rb_ary_cancel_sharing(VALUE ary);
|
||||||
|
|
||||||
static inline VALUE rb_ary_entry_internal(VALUE ary, long offset);
|
static inline VALUE rb_ary_entry_internal(VALUE ary, long offset);
|
||||||
static inline bool ARY_PTR_USING_P(VALUE ary);
|
static inline bool ARY_PTR_USING_P(VALUE ary);
|
||||||
static inline void RARY_TRANSIENT_SET(VALUE ary);
|
static inline void RARY_TRANSIENT_SET(VALUE ary);
|
||||||
|
|
5
ractor.c
5
ractor.c
|
@ -2314,7 +2314,7 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
|
||||||
|
|
||||||
case T_ARRAY:
|
case T_ARRAY:
|
||||||
{
|
{
|
||||||
rb_ary_modify(obj);
|
rb_ary_cancel_sharing(obj);
|
||||||
#if USE_TRANSIENT_HEAP
|
#if USE_TRANSIENT_HEAP
|
||||||
if (data->move) rb_ary_transient_heap_evacuate(obj, TRUE);
|
if (data->move) rb_ary_transient_heap_evacuate(obj, TRUE);
|
||||||
#endif
|
#endif
|
||||||
|
@ -2537,7 +2537,8 @@ copy_leave(VALUE obj, struct obj_traverse_replace_data *data)
|
||||||
return traverse_cont;
|
return traverse_cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE ractor_copy(VALUE obj)
|
static VALUE
|
||||||
|
ractor_copy(VALUE obj)
|
||||||
{
|
{
|
||||||
VALUE val = rb_obj_traverse_replace(obj, copy_enter, copy_leave, false);
|
VALUE val = rb_obj_traverse_replace(obj, copy_enter, copy_leave, false);
|
||||||
if (val != Qundef) {
|
if (val != Qundef) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче