From ef276858d9295208add48e27208c69184dc50472 Mon Sep 17 00:00:00 2001 From: KJ Tsanaktsidis Date: Mon, 22 Jan 2024 16:22:14 +1100 Subject: [PATCH] Trigger postponed jobs on running_ec if that is available Currently, any postponed job triggered from a non-ruby thread gets sent to the main thread, but if the main thread is sleeping it won't be checking ints. Instead, we should try and interrupt running_ec if that's possible, and only fall back to the main thread if it's not. [Bug #20197] --- ractor.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ractor.c b/ractor.c index 4d47e75a6c..f7b251a8dc 100644 --- a/ractor.c +++ b/ractor.c @@ -2481,6 +2481,22 @@ rb_ractor_terminate_all(void) rb_execution_context_t * rb_vm_main_ractor_ec(rb_vm_t *vm) { + /* This code needs to carefully work around two bugs: + * - Bug #20016: When M:N threading is enabled, running_ec is NULL if no thread is + * actually currently running (as opposed to without M:N threading, when + * running_ec will still point to the _last_ thread which ran) + * - Bug #20197: If the main thread is sleeping, setting its postponed job + * interrupt flag is pointless; it won't look at the flag until it stops sleeping + * for some reason. It would be better to set the flag on the running ec, which + * will presumably look at it soon. + * + * Solution: use running_ec if it's set, otherwise fall back to the main thread ec. + * This is still susceptible to some rare race conditions (what if the last thread + * to run just entered a long-running sleep?), but seems like the best balance of + * robustness and complexity. + */ + rb_execution_context_t *running_ec = vm->ractor.main_ractor->threads.running_ec; + if (running_ec) { return running_ec; } return vm->ractor.main_thread->ec; }