From 69b4671729b79d545c0b0a6ae70a3cc419f31301 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 21 Jan 2021 14:29:29 -0800 Subject: [PATCH] Use main Ractor EC on threads without EC Previously in threads which weren't created to running Ruby (which includes the timer thread), calling rb_postponed_job_register_one as well as probably similar hooks would cause a segfault due to the now-thread-local EC being NULL. This was particularly a problem for profiling tools (like stackprof), which rely on signal handlers, which may be sent to any thread in the process including those not managed by Ruby. --- ext/-test-/postponed_job/postponed_job.c | 27 +++++++++++++++++++ .../-ext-/postponed_job/test_postponed_job.rb | 5 ++++ vm_core.h | 7 +++++ 3 files changed, 39 insertions(+) diff --git a/ext/-test-/postponed_job/postponed_job.c b/ext/-test-/postponed_job/postponed_job.c index d8684d475a45..d7d318594110 100644 --- a/ext/-test-/postponed_job/postponed_job.c +++ b/ext/-test-/postponed_job/postponed_job.c @@ -1,3 +1,5 @@ +#include + #include "ruby.h" #include "ruby/debug.h" @@ -58,6 +60,30 @@ pjob_call_direct(VALUE self, VALUE obj) return self; } +static void * +pjob_register_in_c_thread_i(void *obj) +{ + rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj); + rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj); + rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj); + return NULL; +} + +static VALUE +pjob_register_in_c_thread(VALUE self, VALUE obj) +{ + pthread_t thread; + if(pthread_create(&thread, NULL, pjob_register_in_c_thread_i, obj)) { + return Qfalse; + } + + if(pthread_join(thread, NULL)) { + return Qfalse; + } + + return Qtrue; +} + void Init_postponed_job(VALUE self) { @@ -65,5 +91,6 @@ Init_postponed_job(VALUE self) rb_define_module_function(mBug, "postponed_job_register", pjob_register, 1); rb_define_module_function(mBug, "postponed_job_register_one", pjob_register_one, 1); rb_define_module_function(mBug, "postponed_job_call_direct", pjob_call_direct, 1); + rb_define_module_function(mBug, "postponed_job_register_in_c_thread", pjob_register_in_c_thread, 1); } diff --git a/test/-ext-/postponed_job/test_postponed_job.rb b/test/-ext-/postponed_job/test_postponed_job.rb index 7dc28776d0c5..22b6a02c06aa 100644 --- a/test/-ext-/postponed_job/test_postponed_job.rb +++ b/test/-ext-/postponed_job/test_postponed_job.rb @@ -25,4 +25,9 @@ def test_register Bug.postponed_job_register_one(ary = []) assert_equal [1], ary end + + def test_register_in_c_thread + assert Bug.postponed_job_register_in_c_thread(ary = []) + assert_equal [1], ary + end end diff --git a/vm_core.h b/vm_core.h index 5f8d4ab87670..b67e5de8835e 100644 --- a/vm_core.h +++ b/vm_core.h @@ -1788,6 +1788,8 @@ rb_ec_vm_ptr(const rb_execution_context_t *ec) } } +static inline rb_vm_t * rb_current_vm(void); + static inline rb_execution_context_t * rb_current_execution_context(void) { @@ -1800,6 +1802,11 @@ rb_current_execution_context(void) #else rb_execution_context_t *ec = native_tls_get(ruby_current_ec_key); #endif + + if (ec == NULL) { + ec = rb_vm_main_ractor_ec(GET_VM()); + } + VM_ASSERT(ec != NULL); return ec; }