lib/async/scheduler.rb in async-2.6.5 vs lib/async/scheduler.rb in async-2.7.0

- old
+ new

@@ -163,32 +163,69 @@ # See <https://github.com/socketry/async/issues/180> for more details. hostname = hostname.split("%", 2).first ::Resolv.getaddresses(hostname) end + + if IO.method_defined?(:timeout) + private def get_timeout(io) + io.timeout + end + else + private def get_timeout(io) + nil + end + end + # @asynchronous May be non-blocking.. def io_wait(io, events, timeout = nil) fiber = Fiber.current if timeout + # If an explicit timeout is specified, we expect that the user will handle it themselves: timer = @timers.after(timeout) do fiber.transfer end + elsif timeout = get_timeout(io) + # Otherwise, if we default to the io's timeout, we raise an exception: + timer = @timers.after(timeout) do + fiber.raise(::IO::TimeoutError, "Timeout while waiting for IO to become ready!") + end end return @selector.io_wait(fiber, io, events) ensure timer&.cancel end - + if ::IO::Event::Support.buffer? def io_read(io, buffer, length, offset = 0) - @selector.io_read(Fiber.current, io, buffer, length, offset) + fiber = Fiber.current + + if timeout = get_timeout(io) + timer = @timers.after(timeout) do + fiber.raise(::IO::TimeoutError, "execution expired") + end + end + + @selector.io_read(fiber, io, buffer, length, offset) + ensure + timer&.cancel end if RUBY_ENGINE != "ruby" || RUBY_VERSION >= "3.3.0" def io_write(io, buffer, length, offset = 0) - @selector.io_write(Fiber.current, io, buffer, length, offset) + fiber = Fiber.current + + if timeout = get_timeout(io) + timer = @timers.after(timeout) do + fiber.raise(::IO::TimeoutError, "execution expired") + end + end + + @selector.io_write(fiber, io, buffer, length, offset) + ensure + timer&.cancel end end end # Wait for the specified process ID to exit.