diff --git a/lib/async/scheduler.rb b/lib/async/scheduler.rb index b4bd3d12..4efe82aa 100644 --- a/lib/async/scheduler.rb +++ b/lib/async/scheduler.rb @@ -171,17 +171,11 @@ def io_wait(io, events, timeout = nil) if timeout timer = @timers.after(timeout) do - fiber.raise(TimeoutError) + fiber.transfer end end - # Console.logger.info(self, "-> io_wait", fiber, io, events) - events = @selector.io_wait(fiber, io, events) - # Console.logger.info(self, "<- io_wait", fiber, io, events) - - return events - rescue TimeoutError - return false + return @selector.io_wait(fiber, io, events) ensure timer&.cancel end diff --git a/test/async/task.rb b/test/async/task.rb index 4857a04e..d1200a38 100644 --- a/test/async/task.rb +++ b/test/async/task.rb @@ -596,12 +596,14 @@ def after expect(state).to be == :timeout end - it "will timeout while getting from stdin" do + it "will timeout while getting from input" do + input, output = IO.pipe error = nil reactor.async do |task| begin - task.with_timeout(0.1) {STDIN.gets} + # This can invoke `io_wait`, which previously had `rescue TimeoutError`, causing the timeout to be ignored. + task.with_timeout(0.1) {input.gets} rescue Async::TimeoutError => error # Ignore. end @@ -610,6 +612,9 @@ def after reactor.run expect(error).to be_a(Async::TimeoutError) + ensure + input.close + output.close end it "won't timeout if execution completes in time" do