diff options
author | Koichi Sasada <ko1@atdot.net> | 2020-10-30 00:32:53 +0900 |
---|---|---|
committer | Koichi Sasada <ko1@atdot.net> | 2020-10-30 03:12:09 +0900 |
commit | 5d97bdc2dcb835c877010daa033cc2b1dfeb86d6 (patch) | |
tree | 147bbd2e687a9db2bbd5fede670690eae644ebe1 /ractor.c | |
parent | 502d6d845946f367ffb6e972e9c4ac401da94e99 (diff) | |
download | ruby-5d97bdc2dcb835c877010daa033cc2b1dfeb86d6.tar.gz |
Ractor.make_shareable(a_proc)
Ractor.make_shareable() supports Proc object if
(1) a Proc only read outer local variables (no assignments)
(2) read outer local variables are shareable.
Read local variables are stored in a snapshot, so after making
shareable Proc, any assignments are not affeect like that:
```ruby
a = 1
pr = Ractor.make_shareable(Proc.new{p a})
pr.call #=> 1
a = 2
pr.call #=> 1 # `a = 2` doesn't affect
```
[Feature #17284]
Diffstat (limited to 'ractor.c')
-rw-r--r-- | ractor.c | 44 |
1 files changed, 35 insertions, 9 deletions
@@ -21,6 +21,12 @@ static VALUE rb_eRactorMovedError; static VALUE rb_eRactorClosedError; static VALUE rb_cRactorMovedObject; +VALUE +rb_ractor_error_class(void) +{ + return rb_eRactorError; +} + RUBY_SYMBOL_EXPORT_BEGIN // to share with MJIT bool ruby_multi_ractor; @@ -2069,28 +2075,44 @@ rb_obj_traverse(VALUE obj, } static int -frozen_shareable_p(VALUE obj) +frozen_shareable_p(VALUE obj, bool *made_shareable) { - if (!RB_TYPE_P(obj, T_DATA) || - (RTYPEDDATA_P(obj) && - RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_FROZEN_SHAREABLE)) { + if (!RB_TYPE_P(obj, T_DATA)) { return true; } - else { - return false; + else if (RTYPEDDATA_P(obj)) { + const rb_data_type_t *type = RTYPEDDATA_TYPE(obj); + if (type->flags & RUBY_TYPED_FROZEN_SHAREABLE) { + return true; + } + else if (made_shareable && rb_obj_is_proc(obj)) { + // special path to make shareable Proc. + rb_proc_ractor_make_shareable(obj); + *made_shareable = true; + VM_ASSERT(RB_OBJ_SHAREABLE_P(obj)); + return false; + } } + + return false; } static enum obj_traverse_iterator_result make_shareable_check_shareable(VALUE obj) { VM_ASSERT(!SPECIAL_CONST_P(obj)); + bool made_shareable = false; if (RB_OBJ_SHAREABLE_P(obj)) { return traverse_skip; } - else if (!frozen_shareable_p(obj)) { - rb_raise(rb_eRactorError, "can not make shareable object for %"PRIsVALUE, obj); + else if (!frozen_shareable_p(obj, &made_shareable)) { + if (made_shareable) { + return traverse_skip; + } + else { + rb_raise(rb_eRactorError, "can not make shareable object for %"PRIsVALUE, obj); + } } if (!RB_OBJ_FROZEN_RAW(obj)) { @@ -2099,6 +2121,10 @@ make_shareable_check_shareable(VALUE obj) if (UNLIKELY(!RB_OBJ_FROZEN_RAW(obj))) { rb_raise(rb_eRactorError, "#freeze does not freeze object correctly"); } + + if (RB_OBJ_SHAREABLE_P(obj)) { + return traverse_skip; + } } return traverse_cont; @@ -2134,7 +2160,7 @@ shareable_p_enter(VALUE obj) return traverse_skip; } else if (RB_OBJ_FROZEN_RAW(obj) && - frozen_shareable_p(obj)) { + frozen_shareable_p(obj, NULL)) { return traverse_cont; } |