diff options
author | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2020-11-30 16:07:36 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-30 16:07:36 +0900 |
commit | 930a135524382ddd80c0608a7593b6cdfceee846 (patch) | |
tree | 657d033875f462a3b8b9571a30d9657e08ae08b9 | |
parent | 555bd83a8e8b1e859f698089cbbd9ad938159a0e (diff) | |
download | ruby-930a135524382ddd80c0608a7593b6cdfceee846.tar.gz |
Fixed Ractor.shareable? on cross-recursive objects [Bug #17344]
-rw-r--r-- | bootstraptest/test_ractor.rb | 9 | ||||
-rw-r--r-- | ractor.c | 38 |
2 files changed, 41 insertions, 6 deletions
diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb index d5d78d7ad9..6bd00d546f 100644 --- a/bootstraptest/test_ractor.rb +++ b/bootstraptest/test_ractor.rb @@ -975,6 +975,15 @@ assert_equal 'true', %q{ Ractor.shareable?(pr) } +# Ractor.shareable?(recursive_objects) +assert_equal '[false, false]', %q{ + y = [] + x = [y, {}].freeze + y << x + y.freeze + [Ractor.shareable?(x), Ractor.shareable?(y)] +} + # define_method() can invoke different Ractor's proc if the proc is shareable. assert_equal '1', %q{ class C @@ -1805,6 +1805,9 @@ enum obj_traverse_iterator_result { typedef enum obj_traverse_iterator_result (*rb_obj_traverse_enter_func)(VALUE obj); typedef enum obj_traverse_iterator_result (*rb_obj_traverse_leave_func)(VALUE obj); +typedef enum obj_traverse_iterator_result (*rb_obj_traverse_final_func)(VALUE obj); + +static enum obj_traverse_iterator_result null_leave(VALUE obj); struct obj_traverse_data { rb_obj_traverse_enter_func enter_func; @@ -1979,12 +1982,29 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data) } } +struct rb_obj_traverse_final_data { + rb_obj_traverse_final_func final_func; + int stopped; +}; + +static int +obj_traverse_final_i(st_data_t key, st_data_t val, st_data_t arg) +{ + struct rb_obj_traverse_final_data *data = (void *)arg; + if (data->final_func(key)) { + data->stopped = 1; + return ST_STOP; + } + return ST_CONTINUE; +} + // 0: traverse all // 1: stopped static int rb_obj_traverse(VALUE obj, rb_obj_traverse_enter_func enter_func, - rb_obj_traverse_leave_func leave_func) + rb_obj_traverse_leave_func leave_func, + rb_obj_traverse_final_func final_func) { struct obj_traverse_data data = { .enter_func = enter_func, @@ -1992,7 +2012,13 @@ rb_obj_traverse(VALUE obj, .rec = NULL, }; - return obj_traverse_i(obj, &data); + if (obj_traverse_i(obj, &data)) return 1; + if (final_func && data.rec) { + struct rb_obj_traverse_final_data f = {final_func, 0}; + st_foreach(data.rec, obj_traverse_final_i, (st_data_t)&f); + return f.stopped; + } + return 0; } static int @@ -2063,7 +2089,7 @@ rb_ractor_make_shareable(VALUE obj) { rb_obj_traverse(obj, make_shareable_check_shareable, - mark_shareable); + mark_shareable, mark_shareable); return obj; } @@ -2092,7 +2118,7 @@ MJIT_FUNC_EXPORTED bool rb_ractor_shareable_p_continue(VALUE obj) { if (rb_obj_traverse(obj, - shareable_p_enter, + shareable_p_enter, null_leave, mark_shareable)) { return false; } @@ -2113,20 +2139,20 @@ reset_belonging_enter(VALUE obj) return traverse_cont; } } +#endif static enum obj_traverse_iterator_result null_leave(VALUE obj) { return traverse_cont; } -#endif static VALUE ractor_reset_belonging(VALUE obj) { #if RACTOR_CHECK_MODE > 0 rp(obj); - rb_obj_traverse(obj, reset_belonging_enter, null_leave); + rb_obj_traverse(obj, reset_belonging_enter, null_leave, NULL); #endif return obj; } |