From: "luke-gru (Luke Gruber) via ruby-core" Date: 2026-07-28T18:19:55+00:00 Subject: [ruby-core:126186] [Ruby Bug#22211] Fiber::Scheduler stalls on Ractor::Port.receive Issue #22211 has been updated by luke-gru (Luke Gruber). The tricky part in integrating the fiber scheduler with `Ractor::Port` `send/receive` is what to do when you want to wakeup (unblock) a fiber on another Ractor. Normally unblocking a fiber is done on the same Ractor and it's done in a context where you can call directly into `rb_fiber_scheduler_unblock`. When the Fiber Scheduler is on a different Ractor, you can't call its unblock method directly (and a Ruby thread may not even be running on that Ractor. It could be in a syscall, etc.). What we could do is have a special high priority Ruby thread on each Ractor that only calls Fiber Scheduler unblock methods. When you send on a port, you queue up the scheduler unblock operation on that thread and then set the thread to `ready`. The thread scheduler always checks if this thread is ready before dequeuing a real thread, and if so it runs the unblock method. Even that's not ideal because it would go through a thread switch and a fiber switch every time you send to a Ractor that has a Fib er Scheduler, but it's the best I can come up with right now. I created a branch [here](https://github.com/luke-gruber/ruby/tree/port_send_receive_fiber_scheduler) just for experimentation. Right now it creates a new thread on each `Port#send` (not ideal). I'll work on caching the thread soon. Scheduler work is not our priority at the moment as we're looking into making GC faster with Ractors (ractor-local GC). However I might work on this a bit if I have some time. ---------------------------------------- Bug #22211: Fiber::Scheduler stalls on Ractor::Port.receive https://bugs.ruby-lang.org/issues/22211#change-118262 * Author: rkh (Konstantin Haase) * Status: Open * Assignee: ractor * ruby -v: ruby 4.1.0dev (2026-07-24T12:18:38Z master 180b664bd9) +PRISM [arm64-darwin25] * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- Quickly upfront: This might be a duplicate of #20276, and let me know if the official solution is still to launch a thread for each port so it can block (or add some more complex thread orchestration). Anyway, I think `Ractor::Port#receive` should call `Fiber::Scheduler#block`/`Fiber::Scheduler#unblock` if a scheduler is set (or some other hook), the way that `Thread::Queue` does. Instead, it completely blocks the scheduler. Example to reproduce: ``` ruby Warning[:experimental] = false class Scheduler def initialize @fiber = Fiber.current @blocked = Set.new @ready = Queue.new end def scheduler_close @ready.pop.transfer while @blocked.any? end def block(blocker, timeout = nil) raise NotImplementedError, "block: timeout not supported" if timeout @blocked << Fiber.current @fiber.transfer ensure @blocked.delete(Fiber.current) end def unblock(blocker, fiber) = @ready << fiber def io_write(io, buffer, offset, length) = Thread.new { buffer.write(io, offset, length) }.value def fiber(&) = Fiber.new(blocking: false, &).tap(&:transfer) def respond_to_missing?(...) = true def method_missing(method, ...) = raise NotImplementedError, "#{method}: not implemented" end Fiber.set_scheduler(Scheduler.new) # This would work: # # queue = Queue.new # Fiber.schedule { puts queue.pop } # queue.push "Hello from Queue!" port = Ractor::Port.new Fiber.schedule { puts port.receive } port.send("Hello from Ractor::Port!") # never gets here ``` -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/