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

ruby-changes:63812

From: Koichi <ko1@a...>
Date: Tue, 1 Dec 2020 15:44:36 +0900 (JST)
Subject: [ruby-changes:63812] 182fb73c40 (master): rb_ext_ractor_safe() to declare ractor-safe ext

https://git.ruby-lang.org/ruby.git/commit/?id=182fb73c40

From 182fb73c40351f917bf44626c44c1adb6cb1aa5a Mon Sep 17 00:00:00 2001
From: Koichi Sasada <ko1@a...>
Date: Mon, 30 Nov 2020 16:18:43 +0900
Subject: rb_ext_ractor_safe() to declare ractor-safe ext

C extensions can violate the ractor-safety, so only ractor-safe
C extensions (C methods) can run on non-main ractors.
rb_ext_ractor_safe(true) declares that the successive
defined methods are ractor-safe. Otherwiwze, defined methods
checked they are invoked in main ractor and raise an error
if invoked at non-main ractors.

[Feature #17307]

diff --git a/include/ruby/internal/intern/load.h b/include/ruby/internal/intern/load.h
index b4c42a0..f9ba542 100644
--- a/include/ruby/internal/intern/load.h
+++ b/include/ruby/internal/intern/load.h
@@ -34,6 +34,10 @@ void rb_provide(const char*); https://github.com/ruby/ruby/blob/trunk/include/ruby/internal/intern/load.h#L34
 VALUE rb_f_require(VALUE, VALUE);
 VALUE rb_require_string(VALUE);
 
+// extension configuration
+void rb_ext_ractor_safe(bool flag);
+#define RB_EXT_RACTOR_SAFE(f) rb_ext_ractor_safe(f)
+
 RBIMPL_SYMBOL_EXPORT_END()
 
 #endif /* RBIMPL_INTERN_LOAD_H */
diff --git a/load.c b/load.c
index 00ae31e..1c17587 100644
--- a/load.c
+++ b/load.c
@@ -997,6 +997,25 @@ rb_resolve_feature_path(VALUE klass, VALUE fname) https://github.com/ruby/ruby/blob/trunk/load.c#L997
     return rb_ary_new_from_args(2, sym, path);
 }
 
+static void
+ext_config_push(rb_thread_t *th, struct rb_ext_config *prev)
+{
+    *prev = th->ext_config;
+    th->ext_config = (struct rb_ext_config){0};
+}
+
+static void
+ext_config_pop(rb_thread_t *th, struct rb_ext_config *prev)
+{
+    th->ext_config = *prev;
+}
+
+void
+rb_ext_ractor_safe(bool flag)
+{
+    GET_THREAD()->ext_config.ractor_safe = flag;
+}
+
 /*
  * returns
  *  0: if already loaded (false)
@@ -1015,6 +1034,8 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception) https://github.com/ruby/ruby/blob/trunk/load.c#L1034
     enum ruby_tag_type state;
     char *volatile ftptr = 0;
     VALUE path;
+    volatile bool reset_ext_config = false;
+    struct rb_ext_config prev_ext_config;
 
     fname = rb_get_path(fname);
     path = rb_str_encode_ospath(fname);
@@ -1045,6 +1066,8 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception) https://github.com/ruby/ruby/blob/trunk/load.c#L1066
 		    break;
 
 		  case 's':
+                    reset_ext_config = true;
+                    ext_config_push(th, &prev_ext_config);
 		    handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
 						    path, VM_BLOCK_HANDLER_NONE, path);
 		    rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
@@ -1055,9 +1078,12 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception) https://github.com/ruby/ruby/blob/trunk/load.c#L1078
 	}
     }
     EC_POP_TAG();
+
     th = rb_ec_thread_ptr(ec);
     th->top_self = self;
     th->top_wrapper = wrapper;
+    if (reset_ext_config) ext_config_pop(th, &prev_ext_config);
+
     if (ftptr) load_unlock(RSTRING_PTR(path), !state);
 
     if (state) {
diff --git a/ractor.c b/ractor.c
index 693bbe2..c895aab 100644
--- a/ractor.c
+++ b/ractor.c
@@ -21,6 +21,7 @@ static VALUE rb_eRactorRemoteError; https://github.com/ruby/ruby/blob/trunk/ractor.c#L21
 static VALUE rb_eRactorMovedError;
 static VALUE rb_eRactorClosedError;
 static VALUE rb_cRactorMovedObject;
+VALUE rb_eRactorUnsafeError;
 
 VALUE
 rb_ractor_error_class(void)
@@ -1670,6 +1671,7 @@ Init_Ractor(void) https://github.com/ruby/ruby/blob/trunk/ractor.c#L1671
     rb_eRactorRemoteError = rb_define_class_under(rb_cRactor, "RemoteError", rb_eRactorError);
     rb_eRactorMovedError  = rb_define_class_under(rb_cRactor, "MovedError",  rb_eRactorError);
     rb_eRactorClosedError = rb_define_class_under(rb_cRactor, "ClosedError", rb_eStopIteration);
+    rb_eRactorUnsafeError = rb_define_class_under(rb_cRactor, "UnsafeError", rb_eRactorError);
 
     rb_cRactorMovedObject = rb_define_class_under(rb_cRactor, "MovedObject", rb_cBasicObject);
     rb_undef_alloc_func(rb_cRactorMovedObject);
diff --git a/vm.c b/vm.c
index 9114ba4..1e1c06e 100644
--- a/vm.c
+++ b/vm.c
@@ -3052,6 +3052,7 @@ th_init(rb_thread_t *th, VALUE self) https://github.com/ruby/ruby/blob/trunk/vm.c#L3052
 #endif
     th->name = Qnil;
     th->report_on_exception = th->vm->thread_report_on_exception;
+    th->ext_config.ractor_safe = true;
 }
 
 static VALUE
diff --git a/vm_core.h b/vm_core.h
index 53bf67c..5ddd7b4 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -912,6 +912,10 @@ void rb_ec_initialize_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t https://github.com/ruby/ruby/blob/trunk/vm_core.h#L912
 // @param ec the execution context to update.
 void rb_ec_clear_vm_stack(rb_execution_context_t *ec);
 
+struct rb_ext_config {
+    bool ractor_safe;
+};
+
 typedef struct rb_ractor_struct rb_ractor_t;
 
 typedef struct rb_thread_struct {
@@ -1000,6 +1004,8 @@ typedef struct rb_thread_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L1004
     /* misc */
     VALUE name;
 
+    struct rb_ext_config ext_config;
+
 #ifdef USE_SIGALTSTACK
     void *altstack;
 #endif
@@ -1994,6 +2000,8 @@ extern void rb_reset_coverages(void); https://github.com/ruby/ruby/blob/trunk/vm_core.h#L2000
 
 void rb_postponed_job_flush(rb_vm_t *vm);
 
+extern VALUE rb_eRactorUnsafeError; // ractor.c
+
 RUBY_SYMBOL_EXPORT_END
 
 #endif /* RUBY_VM_CORE_H */
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index b6ad18c..e6282ca 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -2469,111 +2469,276 @@ vm_call_iseq_setup_tailcall(rb_execution_context_t *ec, rb_control_frame_t *cfp, https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2469
     return Qundef;
 }
 
+static void
+ractor_unsafe_check(void)
+{
+    if (!rb_ractor_main_p()) {
+        rb_raise(rb_eRactorUnsafeError, "ractor unsafe method called from not main ractor");
+    }
+}
+
 static VALUE
 call_cfunc_m2(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
 {
+    ractor_unsafe_check();
     return (*func)(recv, rb_ary_new4(argc, argv));
 }
 
 static VALUE
 call_cfunc_m1(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
 {
+    ractor_unsafe_check();
     return (*func)(argc, argv, recv);
 }
 
 static VALUE
 call_cfunc_0(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
 {
+    ractor_unsafe_check();
     VALUE(*f)(VALUE) = (VALUE(*)(VALUE))func;
     return (*f)(recv);
 }
+
 static VALUE
 call_cfunc_1(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
 {
+    ractor_unsafe_check();
     VALUE(*f)(VALUE, VALUE) = (VALUE(*)(VALUE, VALUE))func;
     return (*f)(recv, argv[0]);
 }
+
 static VALUE
 call_cfunc_2(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
 {
+    ractor_unsafe_check();
     VALUE(*f)(VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE))func;
     return (*f)(recv, argv[0], argv[1]);
 }
+
 static VALUE
 call_cfunc_3(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
 {
+    ractor_unsafe_check();
     VALUE(*f)(VALUE, VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE, VALUE))func;
     return (*f)(recv, argv[0], argv[1], argv[2]);
 }
+
 static VALUE
 call_cfunc_4(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
 {
+    ractor_unsafe_check();
     VALUE(*f)(VALUE, VALUE, VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE))func;
     return (*f)(recv, argv[0], argv[1], argv[2], argv[3]);
 }
+
 static VALUE
 call_cfunc_5(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
 {
+    ractor_unsafe_check();
     VALUE(*f)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE))func;
     return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
 }
+
 static VALUE
 call_cfunc_6(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
 {
+    ractor_unsafe_check();
     VALUE(*f)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE))func;
     return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
 }
+
 static VALUE
 call_cfunc_7(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
 {
+    ractor_unsafe_check();
     VALUE(*f)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE))func;
     return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
 }
+
 static VALUE
 call_cfunc_8(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
 {
+    ractor_unsafe_check();
     VALUE(*f)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE))func;
     return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
 }
+
 static VALUE
 call_cfunc_9(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
 {
+    ractor_unsafe_check();
     VALUE(*f)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE))func;
     return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
 }
+
 static VALUE
 call_cfunc_10(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
 {
+    ractor_unsafe_check();
     VALUE(*f)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE))func;
     return (*f)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
 }
+
 static VALUE
 call_cfunc_11(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS))
 {
+    ractor_unsafe_check();
     VALUE(*f)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE) = (VALUE(*)(VALUE, VALUE, VALUE, VALUE, VA (... truncated)

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

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