diff --git a/lib/io/event/selector/select.rb b/lib/io/event/selector/select.rb index e54fb47c..a76ba14a 100644 --- a/lib/io/event/selector/select.rb +++ b/lib/io/event/selector/select.rb @@ -103,14 +103,23 @@ def alive? self.fiber&.alive? end - def transfer(events) + def dispatch(events, &reactivate) + tail = self.tail if fiber = self.fiber - self.fiber = nil - - fiber.transfer(events & self.events) if fiber.alive? + if fiber.alive? + revents = events & self.events + if revents.zero? + reactivate.call(self) + else + self.fiber = nil + fiber.transfer(revents) + end + else + self.fiber = nil + end end - - self.tail&.transfer(events) + + tail&.dispatch(events, &reactivate) end def invalidate @@ -349,7 +358,10 @@ def select(duration = nil) end ready.each do |io, events| - @waiting.delete(io).transfer(events) + @waiting.delete(io).dispatch(events) do |waiter| + waiter.tail = @waiting[io] + @waiting[io] = waiter + end end return ready.size diff --git a/test/io/event/selector.rb b/test/io/event/selector.rb index 147cd2bd..1a0d4644 100644 --- a/test/io/event/selector.rb +++ b/test/io/event/selector.rb @@ -178,6 +178,48 @@ def transfer expect(writable).to be == true end + it "can read and write from two different fibers (alternate)" do + read_fiber = Fiber.new do + events << :wait_readable + + expect( + selector.io_wait(Fiber.current, local, IO::READABLE) + ).to be == IO::READABLE + + events << :readable + end + + write_fiber = Fiber.new do + events << :wait_writable + + expect( + selector.io_wait(Fiber.current, local, IO::WRITABLE) + ).to be == IO::WRITABLE + + events << :writable + end + + events << :transfer + read_fiber.transfer + write_fiber.transfer + + events << :select1 + selector.select(1) + remote.puts "Hello World" + events << :select2 + selector.select(1) + + expect(events).to be == [ + :transfer, + :wait_readable, + :wait_writable, + :select1, + :writable, + :select2, + :readable, + ] + end + it "can handle exception during wait" do fiber = Fiber.new do events << :wait_readable