From 90a7e2436fd1050b7164392d8a689ba5621ebaf8 Mon Sep 17 00:00:00 2001 From: Keita Urashima Date: Mon, 1 Jun 2026 14:06:24 +0900 Subject: [PATCH] PERF: release GVL while the V8 thread boots the isolate Context.new (multithreaded mode) spawns the V8 thread and then blocks on the late_init barrier while that thread runs v8::Isolate::New (snapshot deserialization) and safe-context setup. barrier_wait is a plain pthread_cond_wait, so the booting Ruby thread holds the GVL the entire time, stalling every other Ruby thread for the full boot. The V8 thread touches no Ruby objects during boot (the snapshot is a C buffer already copied into c->snapshot), so release the GVL around the barrier waits via rb_thread_call_without_gvl. A background thread booting contexts from a snapshot (e.g. a warm-context pool) now overlaps with the main thread instead of freezing it. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../mini_racer_extension.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/ext/mini_racer_extension/mini_racer_extension.c b/ext/mini_racer_extension/mini_racer_extension.c index 496d011..e3adfb8 100644 --- a/ext/mini_racer_extension/mini_racer_extension.c +++ b/ext/mini_racer_extension/mini_racer_extension.c @@ -1603,6 +1603,21 @@ void v8_get_flags(char **p, size_t *n) rb_thread_lock_native_thread(); } +// Blocks until the V8 thread finishes booting the isolate, which includes +// snapshot deserialization (v8::Isolate::New) and safe-context setup. None of +// that touches Ruby objects -- the snapshot is a plain C buffer already copied +// into |c->snapshot| -- so we release the GVL while waiting, letting other Ruby +// threads (e.g. a background pool refilling more contexts) truly run meanwhile. +static void *context_boot_wait(void *arg) +{ + Context *c; + + c = arg; + barrier_wait(&c->early_init); + barrier_wait(&c->late_init); + return NULL; +} + static VALUE context_initialize(int argc, VALUE *argv, VALUE self) { VALUE kwargs, a, k, v; @@ -1670,8 +1685,7 @@ static VALUE context_initialize(int argc, VALUE *argv, VALUE self) pthread_attr_destroy(&attr); if (r) goto fail; - barrier_wait(&c->early_init); - barrier_wait(&c->late_init); + rb_thread_call_without_gvl(context_boot_wait, c, NULL, NULL); } return Qnil; fail: