[前][次][番号順一覧][スレッド一覧]

ruby-changes:63395

From: Koichi <ko1@a...>
Date: Wed, 21 Oct 2020 07:59:43 +0900 (JST)
Subject: [ruby-changes:63395] 2f50936cb9 (master): Ractor.make_shareable(obj)

https://git.ruby-lang.org/ruby.git/commit/?id=2f50936cb9

From 2f50936cb913b7458cbaa03dc4652f1127a7631a Mon Sep 17 00:00:00 2001
From: Koichi Sasada <ko1@a...>
Date: Wed, 21 Oct 2020 00:54:03 +0900
Subject: Ractor.make_shareable(obj)

Introduce new method Ractor.make_shareable(obj) which tries to make
obj shareable object. Protocol is here.

(1) If obj is shareable, it is shareable.
(2) If obj is not a shareable object and if obj can be shareable
    object if it is frozen, then freeze obj. If obj has reachable
    objects (rs), do rs.each{|o| Ractor.make_shareable(o)}
    recursively (recursion is not Ruby-level, but C-level).
(3) Otherwise, raise Ractor::Error. Now T_DATA is not a shareable
    object even if the object is frozen.

If the method finished without error, given obj is marked as
a sharable object.

To allow makng a shareable frozen T_DATA object, then set
`RUBY_TYPED_FROZEN_SHAREABLE` as type->flags. On default,
this flag is not set. It means user defined T_DATA objects are
not allowed to become shareable objects when it is frozen.

You can make any object  shareable by setting FL_SHAREABLE flag,
so if you know that the T_DATA object is shareable (== thread-safe),
set this flag, at creation time for example. `Ractor` object is one
example, which is not a frozen, but a shareable object.

diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb
index f951d4b..6290b73 100644
--- a/bootstraptest/test_ractor.rb
+++ b/bootstraptest/test_ractor.rb
@@ -832,6 +832,80 @@ assert_equal '0', %q{ https://github.com/ruby/ruby/blob/trunk/bootstraptest/test_ractor.rb#L832
   }.take
 }
 
+# Ractor.make_shareable(obj)
+assert_equal 'true', %q{
+  class C
+    def initialize
+      @a = 'foo'
+      @b = 'bar'
+    end
+    attr_reader :a, :b
+  end
+  S = Struct.new(:s1, :s2)
+  str = "hello"
+  str.instance_variable_set("@iv", "hello")
+  /a/ =~ 'a'
+  m = $~
+  class N < Numeric
+    def /(other)
+      1
+    end
+  end
+  ary = []; ary << ary
+
+  a = [[1, ['2', '3']],
+       {Object.new => "hello"},
+       C.new,
+       S.new("x", "y"),
+       ("a".."b"),
+       str,
+       ary,             # cycle
+       /regexp/,
+       /#{'r'.upcase}/,
+       m,
+       Complex(N.new,0),
+       Rational(N.new,0),
+       true,
+       false,
+       nil,
+       1, 1.2, 1+3r, 1+4i, # Numeric
+  ]
+  Ractor.make_shareable(a)
+
+  # check all frozen
+  a.each{|o|
+    raise o.inspect unless o.frozen?
+
+    case o
+    when C
+      raise o.a.inspect unless o.a.frozen?
+      raise o.b.inspect unless o.b.frozen?
+    when Rational
+      raise o.numerator.inspect unless o.numerator.frozen?
+    when Complex
+      raise o.real.inspect unless o.real.frozen?
+    when Array
+      if o[0] == 1
+        raise o[1][1].inspect unless o[1][1].frozen?
+      end
+    when Hash
+      o.each{|k, v|
+        raise k.inspect unless k.frozen?
+        raise v.inspect unless v.frozen?
+      }
+    end
+  }
+
+  Ractor.shareable?(a)
+}
+
+# Ractor.make_shareable(obj) doesn't freeze shareable objects
+assert_equal 'true', %q{
+  r = Ractor.new{}
+  Ractor.make_shareable(a = [r])
+  [a.frozen?, a[0].frozen?] == [true, false]
+}
+
 ###
 ### Synchronization tests
 ###
diff --git a/common.mk b/common.mk
index a8719ca..7b5ab6f 100644
--- a/common.mk
+++ b/common.mk
@@ -10193,10 +10193,17 @@ ractor.$(OBJEXT): $(CCAN_DIR)/list/list.h https://github.com/ruby/ruby/blob/trunk/common.mk#L10193
 ractor.$(OBJEXT): $(CCAN_DIR)/str/str.h
 ractor.$(OBJEXT): $(hdrdir)/ruby/ruby.h
 ractor.$(OBJEXT): $(top_srcdir)/internal/array.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/bignum.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/bits.h
 ractor.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/complex.h
 ractor.$(OBJEXT): $(top_srcdir)/internal/error.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
 ractor.$(OBJEXT): $(top_srcdir)/internal/gc.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/hash.h
 ractor.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/numeric.h
+ractor.$(OBJEXT): $(top_srcdir)/internal/rational.h
 ractor.$(OBJEXT): $(top_srcdir)/internal/serial.h
 ractor.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
 ractor.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -10220,6 +10227,7 @@ ractor.$(OBJEXT): {$(VPATH)}debug.h https://github.com/ruby/ruby/blob/trunk/common.mk#L10227
 ractor.$(OBJEXT): {$(VPATH)}debug_counter.h
 ractor.$(OBJEXT): {$(VPATH)}defines.h
 ractor.$(OBJEXT): {$(VPATH)}encoding.h
+ractor.$(OBJEXT): {$(VPATH)}gc.h
 ractor.$(OBJEXT): {$(VPATH)}id.h
 ractor.$(OBJEXT): {$(VPATH)}id_table.h
 ractor.$(OBJEXT): {$(VPATH)}intern.h
@@ -10381,6 +10389,7 @@ ractor.$(OBJEXT): {$(VPATH)}subst.h https://github.com/ruby/ruby/blob/trunk/common.mk#L10389
 ractor.$(OBJEXT): {$(VPATH)}thread.h
 ractor.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
 ractor.$(OBJEXT): {$(VPATH)}thread_native.h
+ractor.$(OBJEXT): {$(VPATH)}variable.h
 ractor.$(OBJEXT): {$(VPATH)}vm_core.h
 ractor.$(OBJEXT): {$(VPATH)}vm_debug.h
 ractor.$(OBJEXT): {$(VPATH)}vm_opts.h
diff --git a/include/ruby/internal/core/rtypeddata.h b/include/ruby/internal/core/rtypeddata.h
index 3ffe07e..c038e6f 100644
--- a/include/ruby/internal/core/rtypeddata.h
+++ b/include/ruby/internal/core/rtypeddata.h
@@ -52,6 +52,7 @@ https://github.com/ruby/ruby/blob/trunk/include/ruby/internal/core/rtypeddata.h#L52
 #define RTYPEDDATA_P                 RTYPEDDATA_P
 #define RTYPEDDATA_TYPE              RTYPEDDATA_TYPE
 #define RUBY_TYPED_FREE_IMMEDIATELY  RUBY_TYPED_FREE_IMMEDIATELY
+#define RUBY_TYPED_FROZEN_SHAREABLE  RUBY_TYPED_FROZEN_SHAREABLE
 #define RUBY_TYPED_WB_PROTECTED      RUBY_TYPED_WB_PROTECTED
 #define RUBY_TYPED_PROMOTED1         RUBY_TYPED_PROMOTED1
 /** @endcond */
@@ -59,6 +60,7 @@ https://github.com/ruby/ruby/blob/trunk/include/ruby/internal/core/rtypeddata.h#L60
 /* bits for rb_data_type_struct::flags */
 enum rbimpl_typeddata_flags {
     RUBY_TYPED_FREE_IMMEDIATELY = 1,
+    RUBY_TYPED_FROZEN_SHAREABLE = RUBY_FL_SHAREABLE,
     RUBY_TYPED_WB_PROTECTED     = RUBY_FL_WB_PROTECTED, /* THIS FLAG DEPENDS ON Ruby version */
     RUBY_TYPED_PROMOTED1        = RUBY_FL_PROMOTED1     /* THIS FLAG DEPENDS ON Ruby version */
 };
diff --git a/internal/hash.h b/internal/hash.h
index 237ce58..a4677c5 100644
--- a/internal/hash.h
+++ b/internal/hash.h
@@ -83,6 +83,8 @@ VALUE rb_hash_set_pair(VALUE hash, VALUE pair); https://github.com/ruby/ruby/blob/trunk/internal/hash.h#L83
 int rb_hash_stlike_delete(VALUE hash, st_data_t *pkey, st_data_t *pval);
 int rb_hash_stlike_foreach_with_replace(VALUE hash, st_foreach_check_callback_func *func, st_update_callback_func *replace, st_data_t arg);
 int rb_hash_stlike_update(VALUE hash, st_data_t key, st_update_callback_func *func, st_data_t arg);
+extern st_table *rb_hash_st_table(VALUE hash);
+
 static inline unsigned RHASH_AR_TABLE_SIZE_RAW(VALUE h);
 static inline VALUE RHASH_IFNONE(VALUE h);
 static inline size_t RHASH_SIZE(VALUE h);
@@ -135,7 +137,6 @@ RHASH_AR_TABLE(VALUE h) https://github.com/ruby/ruby/blob/trunk/internal/hash.h#L137
 static inline st_table *
 RHASH_ST_TABLE(VALUE h)
 {
-    extern st_table *rb_hash_st_table(VALUE hash);
     return rb_hash_st_table(h)
 }
 
diff --git a/ractor.c b/ractor.c
index 68ac5a2..8c498a8 100644
--- a/ractor.c
+++ b/ractor.c
@@ -6,8 +6,13 @@ https://github.com/ruby/ruby/blob/trunk/ractor.c#L6
 #include "vm_core.h"
 #include "vm_sync.h"
 #include "ractor.h"
+#include "internal/complex.h"
 #include "internal/error.h"
+#include "internal/hash.h"
+#include "internal/rational.h"
 #include "internal/struct.h"
+#include "variable.h"
+#include "gc.h"
 
 static VALUE rb_cRactor;
 static VALUE rb_eRactorError;
@@ -1743,8 +1748,6 @@ rb_vm_main_ractor_ec(rb_vm_t *vm) https://github.com/ruby/ruby/blob/trunk/ractor.c#L1748
     return vm->ractor.main_ractor->threads.running_ec;
 }
 
-#include "ractor.rbinc"
-
 static VALUE
 ractor_moved_missing(int argc, VALUE *argv, VALUE self)
 {
@@ -1777,128 +1780,6 @@ Init_Ractor(void) https://github.com/ruby/ruby/blob/trunk/ractor.c#L1780
     rb_obj_freeze(rb_cRactorMovedObject);
 }
 
-static int
-rb_ractor_shareable_p_hash_i(VALUE key, VALUE value, VALUE arg)
-{
-    // TODO: should we need to avoid recursion to prevent stack overflow?
-    if (!rb_ractor_shareable_p(key) || !rb_ractor_shareable_p(value)) {
-        bool *shareable = (bool*)arg;
-        *shareable = false;
-        return ST_STOP;
-    }
-    return ST_CONTINUE;
-}
-
-static bool
-ractor_struct_shareable_members_p(VALUE obj)
-{
-    VM_ASSERT(RB_TYPE_P(obj, T_STRUCT));
-
-    long len = RSTRUCT_LEN(obj);
-    const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
-
-    for (long i=0; i<len; i++) {
-        if (!rb_ractor_shareable_p(ptr[i])) {
-            return false;
-        }
-    }
-    return true;
-}
-
-static bool
-ractor_obj_ivars_shareable_p(VALUE obj)
-{
-    uint32_t len = ROBJECT_NUMIV(obj);
-    VALUE *ptr = ROBJECT_IVPTR(obj);
-
-    for (uint32_t i=0; i<len; i++) {
-        VALUE val = ptr[i];
-        if (val != Qundef && !rb_ractor_shareable_p(ptr[i])) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-MJIT_FUNC_EXPORTED bool
-rb_ractor_shareable_p_continue(VALUE obj)
-{
-    switch (BUILTIN_TYPE(obj)) {
-      case T_CLASS:
-      case T_MODULE:
-      case T_ICLASS:
-        goto shareable;
-
-      case T_FLOAT:
-      case T_COMPLEX:
-      case T_RATIONAL:
-      case T_BIGNUM:
-      case T_SYMBOL:
-        VM_ASSERT(RB_OBJ_FROZEN_RAW(obj));
-        goto shareable;
-
-      case T_STRING:
-      case T_REGEXP:
-        if (RB_OBJ_FROZEN_RAW(obj) &&
-            !FL_TEST_RAW(obj, RUBY_FL_EXIVAR)) {
-            goto shareable;
-        }
-        return false;
-      case T_ARRAY:
-        if (!RB_OBJ_FROZEN_RAW(obj) ||
-            FL_TEST_RAW(obj, RUBY_FL_EXIVAR)) {
-            return false;
-        }
-        else {
-            for (int i = 0; i < RARRAY_LEN(obj); i++) {
-                if (!rb_ractor_shareable_p(rb_ary_entry(obj, i))) r (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]