diff options
author | Luke Gruber <[email protected]> | 2025-05-12 18:03:22 -0400 |
---|---|---|
committer | Aaron Patterson <[email protected]> | 2025-05-13 13:23:57 -0700 |
commit | 1d4822a175a0dfccca8f252b0e757a1991bd54f9 (patch) | |
tree | 442d4f6ede7999b141403b10ece794569e5b5d17 /vm.c | |
parent | 2fee379f8f0be08be49c1fccbb37cb2a06834b24 (diff) |
Get ractor message passing working with > 1 thread sending/receiving values in same ractor
Rework ractors so that any ractor action (Ractor.receive, Ractor#send, Ractor.yield, Ractor#take,
Ractor.select) will operate on the thread that called the action. It will put that thread to sleep if
it's a blocking function and it needs to put it to sleep, and the awakening action (Ractor.yield,
Ractor#send) will wake up the blocked thread.
Before this change every blocking ractor action was associated with the ractor struct and its fields.
If a ractor called Ractor.receive, its wait status was wait_receiving, and when another ractor calls
r.send on it, it will look for that status in the ractor struct fields and wake it up. The problem was that
what if 2 threads call blocking ractor actions in the same ractor. Imagine if 1 thread has called Ractor.receive
and another r.take. Then, when a different ractor calls r.send on it, it doesn't know which ruby thread is associated
to which ractor action, so what ruby thread should it schedule? This change moves some fields onto the ruby thread
itself so that ruby threads are the ones that have ractor blocking statuses, and threads are then specifically scheduled
when unblocked.
Fixes [#17624]
Fixes [#21037]
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/12633
Diffstat (limited to 'vm.c')
-rw-r--r-- | vm.c | 5 |
1 files changed, 5 insertions, 0 deletions
@@ -3556,6 +3556,7 @@ thread_mark(void *ptr) rb_gc_mark(th->last_status); rb_gc_mark(th->locking_mutex); rb_gc_mark(th->name); + rb_gc_mark(th->ractor_waiting.receiving_mutex); rb_gc_mark(th->scheduler); @@ -3717,6 +3718,10 @@ th_init(rb_thread_t *th, VALUE self, rb_vm_t *vm) th->ext_config.ractor_safe = true; ccan_list_head_init(&th->interrupt_exec_tasks); + ccan_list_node_init(&th->ractor_waiting.waiting_node); +#ifndef RUBY_THREAD_PTHREAD_H + rb_native_cond_initialize(&th->ractor_waiting.cond); +#endif #if USE_RUBY_DEBUG_LOG static rb_atomic_t thread_serial = 1; |