Module: Winloop
- Defined in:
- lib/winloop.rb,
lib/winloop/version.rb,
lib/winloop/scheduler.rb,
ext/winloop/winloop.c
Overview
winloop — a native Windows (IOCP) Fiber Scheduler for MRI Ruby.
require "winloop"
Winloop.run do
server = TCPServer.new("127.0.0.1", 9292)
loop do
client = server.accept # io_wait via AFD poll
Fiber.schedule do # one fiber per connection
while (line = client.gets) # io_read via recv_nonblock + io_wait
client.write(line)
end
client.close
end
end
end
All blocking socket I/O, sleeps, timeouts and Mutex/Queue/Thread#join inside the block run cooperatively on a single thread, driven by one I/O Completion Port. See Winloop::Scheduler for the hook implementations.
Defined Under Namespace
Classes: Backend, Error, MinHeap, Scheduler
Constant Summary collapse
- VERSION =
"0.1.0"- READABLE =
Export the Ruby IO event bits the scheduler/backend agree on.
INT2NUM(RB_READABLE)
- WRITABLE =
INT2NUM(RB_WRITABLE)
- PRIORITY =
INT2NUM(RB_PRIORITY)
Class Method Summary collapse
-
.run ⇒ Object
Install a fresh Winloop::Scheduler on the current thread, run ‘block` inside a non-blocking fiber, drive the event loop until every scheduled fiber has finished, and return the block’s value.
-
.supported? ⇒ Boolean
True if the IOCP/AFD backend is available on this platform.
Class Method Details
.run ⇒ Object
Install a fresh Winloop::Scheduler on the current thread, run ‘block` inside a non-blocking fiber, drive the event loop until every scheduled fiber has finished, and return the block’s value.
Nesting is not supported; if a scheduler is already installed, the block is simply scheduled on it.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/winloop.rb', line 52 def run raise ArgumentError, "Winloop.run requires a block" unless block_given? # Already inside a scheduler (e.g. a nested Winloop.run within a fiber): just # run the block here — blocking operations already cooperate with that loop. return yield if Fiber.scheduler scheduler = Scheduler.new Fiber.set_scheduler(scheduler) result = nil error = nil Fiber.schedule do begin result = yield rescue Exception => e # rubocop:disable Lint/RescueException error = e end end scheduler.close # drives the loop to completion raise error if error result ensure # Detach our (now-closed) scheduler so subsequent ordinary I/O on this # thread doesn't hit a closed backend. Safe here: we are on the main fiber # and close has already returned (the reentrant-close trap only bites when # set_scheduler(nil) is called from *inside* #close during finalization). Fiber.set_scheduler(nil) if Fiber.scheduler.equal?(scheduler) end |
.supported? ⇒ Boolean
True if the IOCP/AFD backend is available on this platform.
42 43 44 |
# File 'lib/winloop.rb', line 42 def supported? const_defined?(:Backend) end |