diff --git a/lib/async/scheduler.rb b/lib/async/scheduler.rb index 45f972fa..46610357 100644 --- a/lib/async/scheduler.rb +++ b/lib/async/scheduler.rb @@ -685,6 +685,7 @@ def process_fork @children = nil @selector = nil @timers = nil + @blocked = 0 # Close the scheduler: Fiber.set_scheduler(nil) diff --git a/releases.md b/releases.md index db113ed9..420aae5c 100644 --- a/releases.md +++ b/releases.md @@ -1,5 +1,9 @@ # Releases +## Unreleased + + - Fixed scheduler cleanup after forking while other fibers are blocked. + ## v2.43.0 - Propagate cancellation causes through task trees so child tasks observe the original cancellation cause. diff --git a/test/process/fork.rb b/test/process/fork.rb index 42885389..8b28c0c3 100644 --- a/test/process/fork.rb +++ b/test/process/fork.rb @@ -44,5 +44,28 @@ Process.waitpid(pid) if pid end end + + it "can fork while another fiber is blocked" do + r, w = IO.pipe + queue = Thread::Queue.new + + Async do |task| + blocked_task = task.async do + queue.pop + end + + pid = Process.fork do + # Child process: + w.write("hello") + end + + # Parent process: + w.close + expect(r.read).to be == "hello" + ensure + blocked_task&.stop + Process.waitpid(pid) if pid + end + end end end