diff --git a/fixtures/io/event/test_scheduler.rb b/fixtures/io/event/test_scheduler.rb index 202105de..7faed994 100644 --- a/fixtures/io/event/test_scheduler.rb +++ b/fixtures/io/event/test_scheduler.rb @@ -41,6 +41,7 @@ def initialize(selector: nil, worker_pool: nil, maximum_worker_count: nil) # Track the number of fibers that are blocked. @blocked = 0 + @blocking = {} end # @attribute [WorkerPool] The worker pool used for executing blocking operations. @@ -80,8 +81,10 @@ def block(blocker, timeout = nil) begin @blocked += 1 + @blocking[fiber] = true @selector.transfer ensure + @blocking.delete(fiber) @blocked -= 1 end ensure diff --git a/test/io/event/worker_pool.rb b/test/io/event/worker_pool.rb index c21126da..a0bf1eda 100644 --- a/test/io/event/worker_pool.rb +++ b/test/io/event/worker_pool.rb @@ -123,6 +123,34 @@ expect(result[:duration]).to be == 0.05 end + it "keeps blocked fibers alive during garbage collection" do + result = nil + + Thread.new do + Fiber.set_scheduler(scheduler) + + gc_thread = Thread.new do + sleep(0.02) + GC.start(full_mark: true, immediate_sweep: true) + end + + Fiber.schedule do + result = IO::Event::WorkerPool.busy(duration: 0.1) + end + + scheduler.run + gc_thread.value + ensure + Fiber.set_scheduler(nil) + scheduler.close + end.value + + expect(result).to have_keys( + cancelled: be == false, + result: be == :completed + ) + end + it "can cancel a busy operation using unblock function" do # This tests the cancellation mechanism through rb_thread_call_without_gvl completed = false