From 0157026816cc1d3f4592b444eb97ed8c3e0763a5 Mon Sep 17 00:00:00 2001 From: Fletcher Dares Date: Mon, 11 May 2026 18:21:15 -0400 Subject: [PATCH 1/2] Keep blocked scheduler fibers alive during GC --- fixtures/io/event/test_scheduler.rb | 3 +++ test/io/event/worker_pool.rb | 30 ++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) 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..4f31978f 100644 --- a/test/io/event/worker_pool.rb +++ b/test/io/event/worker_pool.rb @@ -122,7 +122,35 @@ expect(result[:result]).to be == :completed 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 From c14c09b671f21acade9bef5ebdc2bfd626b47646 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Tue, 12 May 2026 09:05:56 +0900 Subject: [PATCH 2/2] RuboCop. --- test/io/event/worker_pool.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/io/event/worker_pool.rb b/test/io/event/worker_pool.rb index 4f31978f..a0bf1eda 100644 --- a/test/io/event/worker_pool.rb +++ b/test/io/event/worker_pool.rb @@ -122,35 +122,35 @@ expect(result[:result]).to be == :completed 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