Skip to content

Commit 9072aa9

Browse files
Use IO::Buffer#copy (>=1MiB) to trigger blocking_operation_wait reliably
IO::Buffer#copy with a large buffer calls rb_nogvl(RB_NOGVL_OFFLOAD_SAFE) in all Ruby versions that have blocking_operation_wait support, rather than relying on a specific version of io_close_fptr. Verified that the hook is called on 3.4 and master. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent df880b2 commit 9072aa9

1 file changed

Lines changed: 9 additions & 14 deletions

File tree

test/fiber/test_blocking_operation_gc.rb

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def blocking_operation_wait(work)
6969
class TestBlockingOperationGC < Test::Unit::TestCase
7070
def omit_unless_supported
7171
omit "GC.compact not supported" unless GC.respond_to?(:compact)
72-
omit "TCPServer not available" unless defined?(TCPServer)
72+
omit "IO::Buffer not available" unless defined?(IO::Buffer)
7373
end
7474

7575
def run_with_scheduler(trigger:)
@@ -78,19 +78,14 @@ def run_with_scheduler(trigger:)
7878
scheduler = BlockingOperationGCScheduler.new(trigger: trigger)
7979
Fiber.set_scheduler(scheduler)
8080

81-
server = TCPServer.new("localhost", 0)
82-
port = server.addr[1]
83-
client = TCPSocket.new("localhost", port)
84-
peer = server.accept
85-
81+
# IO::Buffer#copy with >= 1 MiB triggers rb_nogvl(RB_NOGVL_OFFLOAD_SAFE)
82+
# which calls rb_fiber_scheduler_blocking_operation_wait when a fiber
83+
# scheduler is active. This is the code path we are testing.
8684
Fiber.schedule do
87-
# IO#close calls maygvl_close -> IO_WITHOUT_GVL -> rb_nogvl(RB_NOGVL_OFFLOAD_SAFE)
88-
# -> rb_fiber_scheduler_blocking_operation_wait when a fiber scheduler is active.
89-
server.close
85+
src = IO::Buffer.for("x" * (2 * 1024 * 1024))
86+
dst = IO::Buffer.new(2 * 1024 * 1024)
87+
dst.copy(src)
9088
end
91-
ensure
92-
client&.close rescue nil
93-
peer&.close rescue nil
9489
end.join
9590
scheduler
9691
end
@@ -104,7 +99,7 @@ def test_blocking_operation_gc_compact
10499
omit_unless_supported
105100
assert_nothing_raised do
106101
scheduler = run_with_scheduler(trigger: :compact)
107-
omit "blocking_operation_wait was not called (Ruby version does not route IO#close through it)" if scheduler.blocking_operation_wait_call_count == 0
102+
omit "blocking_operation_wait was not called" if scheduler.blocking_operation_wait_call_count == 0
108103
end
109104
end
110105

@@ -116,7 +111,7 @@ def test_blocking_operation_gc_fiber_switch
116111
omit_unless_supported
117112
assert_nothing_raised do
118113
scheduler = run_with_scheduler(trigger: :fiber_switch)
119-
omit "blocking_operation_wait was not called (Ruby version does not route IO#close through it)" if scheduler.blocking_operation_wait_call_count == 0
114+
omit "blocking_operation_wait was not called" if scheduler.blocking_operation_wait_call_count == 0
120115
end
121116
end
122117
end

0 commit comments

Comments
 (0)