From 54896cd52d916150ca8a53b4542bd42f2a69058a Mon Sep 17 00:00:00 2001 From: Matt Valentine-House Date: Tue, 30 Jun 2020 22:19:18 +0100 Subject: [PATCH] Initialize Mutex's at the start of Init process Running GC requres these Mutex's to be initialised but the code that initialises them (in thread.c) happens after the initialisation of the GC. Normally this wouldn't be a problem because GC wouldn't need to run during the Ruby initialisation process. Since we've added Garbage to the end of an RVALUE, we now reach the end of a transient heap page during the startup process which triggers a GC run - which crashes because the mutex's aren't initialised so the OS rejects the request for the lock. This patch extracts the mutex initialisation from Init_Thread and pulls it right to the top of the ruby initialisation process so they're going to be usable no matter when the GC runs. Initially we tried to workaround this by just moving the ordering of the initialisations in inits.c. This turned into a game of whack a mole as there are dependencies between a lot of these items. We chose this approach as it makes it clearer exactly which code that we are depending on and that it needs to run first in the initialisation queue. --- eval.c | 2 -- inits.c | 1 + thread.c | 13 ++++++++++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/eval.c b/eval.c index b201121fc2de82..52f3cc4e9fff81 100644 --- a/eval.c +++ b/eval.c @@ -88,10 +88,8 @@ ruby_setup(void) EC_PUSH_TAG(GET_EC()); if ((state = EC_EXEC_TAG()) == TAG_NONE) { - rb_gc_disable(); rb_call_inits(); ruby_prog_init(); - rb_gc_enable(); GET_VM()->running = 1; } EC_POP_TAG(); diff --git a/inits.c b/inits.c index ad57b754a462d4..976cb223ec840a 100644 --- a/inits.c +++ b/inits.c @@ -20,6 +20,7 @@ static void Init_builtin_prelude(void); void rb_call_inits(void) { + CALL(Thread_Mutex); #if USE_TRANSIENT_HEAP CALL(TransientHeap); #endif diff --git a/thread.c b/thread.c index e463b72a41925f..8980c8cc597e9c 100644 --- a/thread.c +++ b/thread.c @@ -5255,6 +5255,16 @@ rb_thread_backtrace_locations_m(int argc, VALUE *argv, VALUE thval) return rb_vm_thread_backtrace_locations(argc, argv, thval); } +void +Init_Thread_Mutex() +{ + rb_thread_t *th = GET_THREAD(); + + rb_native_mutex_initialize(&th->vm->waitpid_lock); + rb_native_mutex_initialize(&th->vm->workqueue_lock); + rb_native_mutex_initialize(&th->interrupt_lock); +} + /* * Document-class: ThreadError * @@ -5374,9 +5384,6 @@ Init_Thread(void) /* acquire global vm lock */ gvl_init(th->vm); gvl_acquire(th->vm, th); - rb_native_mutex_initialize(&th->vm->waitpid_lock); - rb_native_mutex_initialize(&th->vm->workqueue_lock); - rb_native_mutex_initialize(&th->interrupt_lock); th->pending_interrupt_queue = rb_ary_tmp_new(0); th->pending_interrupt_queue_checked = 0;