diff options
| author | Koichi Sasada <ko1@atdot.net> | 2025-12-05 01:13:55 +0900 |
|---|---|---|
| committer | Koichi Sasada <ko1@atdot.net> | 2025-12-05 02:28:30 +0900 |
| commit | f2cd772329b8d07e29ed114480ff99ad36acbd75 (patch) | |
| tree | 00ac3ee0d0f422ed458cc8a5abe6929086928e54 | |
| parent | 3730022787086852fa2fbc94ffda6ec8c8fbc0b3 (diff) | |
(experimental) RUBY_TYPED_FROZEN_SHAREABLE_NO_REC
`T_DATA` has a flag `RUBY_TYPED_FROZEN_SHAREABLE` which means
if the `T_DATA` object is frozen, it can be sharable.
On the `Ractor.make_sharable(obj)`, rechable objects from the
`T_DATA` object will be apply `Ractor.make_shareable` recursively.
`RUBY_TYPED_FROZEN_SHAREABLE_NO_REC` is similar to the
`RUBY_TYPED_FROZEN_SHAREABLE`, but doesn't apply `Ractor.make_sharable`
recursively for children.
If it refers to unshareable objects, it will simply raise an error.
I'm not sure this pattern is common or not, so it is not in public.
If we find more cases, we can discuss publication.
| -rw-r--r-- | include/ruby/internal/core/rtypeddata.h | 6 | ||||
| -rw-r--r-- | ractor.c | 50 | ||||
| -rw-r--r-- | ractor_core.h | 3 |
3 files changed, 45 insertions, 14 deletions
diff --git a/include/ruby/internal/core/rtypeddata.h b/include/ruby/internal/core/rtypeddata.h index aaf8f7997c..ee79c2e2a9 100644 --- a/include/ruby/internal/core/rtypeddata.h +++ b/include/ruby/internal/core/rtypeddata.h @@ -157,6 +157,12 @@ rbimpl_typeddata_flags { */ RUBY_TYPED_FROZEN_SHAREABLE = RUBY_FL_SHAREABLE, + // experimental flag + // Similar to RUBY_TYPED_FROZEN_SHAREABLE, but doesn't make shareable + // reachable objects from this T_DATA object on the Ractor.make_shareable. + // If it refers to unsharable objects, simply raise an error. + // RUBY_TYPED_FROZEN_SHAREABLE_NO_REC = RUBY_FL_FINALIZE, + /** * This flag has something to do with our garbage collector. These days * ruby objects are "generational". There are those who are young and @@ -1428,6 +1428,26 @@ allow_frozen_shareable_p(VALUE obj) } static enum obj_traverse_iterator_result +make_shareable_check_shareable_freeze(VALUE obj, enum obj_traverse_iterator_result result) +{ + if (!RB_OBJ_FROZEN_RAW(obj)) { + rb_funcall(obj, idFreeze, 0); + + 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 result; +} + +static int obj_refer_only_shareables_p(VALUE obj); + +static enum obj_traverse_iterator_result make_shareable_check_shareable(VALUE obj) { VM_ASSERT(!SPECIAL_CONST_P(obj)); @@ -1436,7 +1456,21 @@ make_shareable_check_shareable(VALUE obj) return traverse_skip; } else if (!allow_frozen_shareable_p(obj)) { - if (rb_obj_is_proc(obj)) { + VM_ASSERT(RB_TYPE_P(obj, T_DATA)); + const rb_data_type_t *type = RTYPEDDATA_TYPE(obj); + + if (type->flags & RUBY_TYPED_FROZEN_SHAREABLE_NO_REC) { + if (obj_refer_only_shareables_p(obj)) { + make_shareable_check_shareable_freeze(obj, traverse_skip); + RB_OBJ_SET_SHAREABLE(obj); + return traverse_skip; + } + else { + rb_raise(rb_eRactorError, + "can not make shareable object for %+"PRIsVALUE" because it refers unshareable objects", obj); + } + } + else if (rb_obj_is_proc(obj)) { rb_proc_ractor_make_shareable(obj, Qundef); return traverse_cont; } @@ -1466,19 +1500,7 @@ make_shareable_check_shareable(VALUE obj) break; } - if (!RB_OBJ_FROZEN_RAW(obj)) { - rb_funcall(obj, idFreeze, 0); - - 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; + return make_shareable_check_shareable_freeze(obj, traverse_cont); } static enum obj_traverse_iterator_result diff --git a/ractor_core.h b/ractor_core.h index 81374c0769..d6f9d4eda0 100644 --- a/ractor_core.h +++ b/ractor_core.h @@ -9,6 +9,9 @@ #define RACTOR_CHECK_MODE (VM_CHECK_MODE || RUBY_DEBUG) && (SIZEOF_UINT64_T == SIZEOF_VALUE) #endif +// experimental flag because it is not sure it is the common pattern +#define RUBY_TYPED_FROZEN_SHAREABLE_NO_REC RUBY_FL_FINALIZE + struct rb_ractor_sync { // ractor lock rb_nativethread_lock_t lock; |
