summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2025-12-05 01:13:55 +0900
committerKoichi Sasada <ko1@atdot.net>2025-12-05 02:28:30 +0900
commitf2cd772329b8d07e29ed114480ff99ad36acbd75 (patch)
tree00ac3ee0d0f422ed458cc8a5abe6929086928e54
parent3730022787086852fa2fbc94ffda6ec8c8fbc0b3 (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.h6
-rw-r--r--ractor.c50
-rw-r--r--ractor_core.h3
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
diff --git a/ractor.c b/ractor.c
index ea09583c5f..6bd38b6ab8 100644
--- a/ractor.c
+++ b/ractor.c
@@ -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;