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/