summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorSamuel Williams <[email protected]>2025-05-24 20:33:08 +0900
committerSamuel Williams <[email protected]>2025-06-06 13:13:16 +0900
commit81a23c5793fecaff5f75cefe6a6e03dab99df16b (patch)
treea34dfc6ea30ed7cc57ab3b69ea2983abb1951e43 /test
parente093c3145ac7a2efcbc7965e43f29a992316ab64 (diff)
`rb_io_blocking_operation_exit` should not execute with pending interrupts.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/13437
Diffstat (limited to 'test')
-rw-r--r--test/fiber/test_io.rb59
-rw-r--r--test/fiber/test_io_close.rb110
2 files changed, 139 insertions, 30 deletions
diff --git a/test/fiber/test_io.rb b/test/fiber/test_io.rb
index 39e32c5987..eea06f97c8 100644
--- a/test/fiber/test_io.rb
+++ b/test/fiber/test_io.rb
@@ -9,7 +9,7 @@ class TestFiberIO < Test::Unit::TestCase
omit unless defined?(UNIXSocket)
i, o = UNIXSocket.pair
- if RUBY_PLATFORM=~/mswin|mingw/
+ if RUBY_PLATFORM =~ /mswin|mingw/
i.nonblock = true
o.nonblock = true
end
@@ -44,7 +44,7 @@ class TestFiberIO < Test::Unit::TestCase
16.times.map do
Thread.new do
i, o = UNIXSocket.pair
- if RUBY_PLATFORM=~/mswin|mingw/
+ if RUBY_PLATFORM =~ /mswin|mingw/
i.nonblock = true
o.nonblock = true
end
@@ -67,7 +67,7 @@ class TestFiberIO < Test::Unit::TestCase
def test_epipe_on_read
omit unless defined?(UNIXSocket)
- omit "nonblock=true isn't properly supported on Windows" if RUBY_PLATFORM=~/mswin|mingw/
+ omit "nonblock=true isn't properly supported on Windows" if RUBY_PLATFORM =~ /mswin|mingw/
i, o = UNIXSocket.pair
@@ -242,38 +242,37 @@ class TestFiberIO < Test::Unit::TestCase
# Windows has UNIXSocket, but only with VS 2019+
omit "UNIXSocket is not defined!" unless defined?(UNIXSocket)
- i, o = Socket.pair(:UNIX, :STREAM)
- if RUBY_PLATFORM=~/mswin|mingw/
- i.nonblock = true
- o.nonblock = true
- end
+ Socket.pair(:UNIX, :STREAM) do |i, o|
+ if RUBY_PLATFORM =~ /mswin|mingw/
+ i.nonblock = true
+ o.nonblock = true
+ end
- reading_thread = Thread.new do
- Thread.current.report_on_exception = false
- i.wait_readable
- end
+ reading_thread = Thread.new do
+ Thread.current.report_on_exception = false
+ i.wait_readable
+ end
- fs_thread = Thread.new do
- # Wait until the reading thread is blocked on read:
- Thread.pass until reading_thread.status == "sleep"
+ scheduler_thread = Thread.new do
+ # Wait until the reading thread is blocked on read:
+ Thread.pass until reading_thread.status == "sleep"
- scheduler = Scheduler.new
- Fiber.set_scheduler scheduler
- Fiber.schedule do
- i.close
+ scheduler = Scheduler.new
+ Fiber.set_scheduler scheduler
+ Fiber.schedule do
+ i.close
+ end
end
- end
- assert_raise(IOError) { reading_thread.join }
- refute_nil fs_thread.join(5), "expected thread to terminate within 5 seconds"
+ assert_raise(IOError) { reading_thread.join }
+ refute_nil scheduler_thread.join(5), "expected thread to terminate within 5 seconds"
- assert_predicate(i, :closed?)
- ensure
- fs_thread&.kill
- fs_thread&.join rescue nil
- reading_thread&.kill
- reading_thread&.join rescue nil
- i&.close
- o&.close
+ assert_predicate(i, :closed?)
+ ensure
+ scheduler_thread&.kill
+ scheduler_thread&.join rescue nil
+ reading_thread&.kill
+ reading_thread&.join rescue nil
+ end
end
end
diff --git a/test/fiber/test_io_close.rb b/test/fiber/test_io_close.rb
new file mode 100644
index 0000000000..411d709359
--- /dev/null
+++ b/test/fiber/test_io_close.rb
@@ -0,0 +1,110 @@
+# frozen_string_literal: true
+require 'test/unit'
+require_relative 'scheduler'
+
+class TestFiberIOClose < Test::Unit::TestCase
+ def with_socket_pair(&block)
+ omit "UNIXSocket is not defined!" unless defined?(UNIXSocket)
+
+ UNIXSocket.pair do |i, o|
+ if RUBY_PLATFORM =~ /mswin|mingw/
+ i.nonblock = true
+ o.nonblock = true
+ end
+
+ yield i, o
+ end
+ end
+
+ # Problematic on Windows.
+ def test_io_close_across_fibers
+ omit "Interrupting a io_wait read is not supported!" if RUBY_PLATFORM =~ /mswin|mingw/
+
+ with_socket_pair do |i, o|
+ error = nil
+
+ thread = Thread.new do
+ scheduler = Scheduler.new
+ Fiber.set_scheduler scheduler
+
+ Fiber.schedule do
+ i.read
+ rescue => error
+ # Ignore.
+ end
+
+ Fiber.schedule do
+ i.close
+ end
+ end
+
+ thread.join
+
+ assert_instance_of IOError, error
+ assert_match(/closed/, error.message)
+ end
+ end
+
+ # Okay on all platforms.
+ def test_io_close_blocking_thread
+ omit "Interrupting a io_wait read is not supported!" if RUBY_PLATFORM =~ /mswin|mingw/
+
+ with_socket_pair do |i, o|
+ error = nil
+
+ reading_thread = Thread.new do
+ i.read
+ rescue => error
+ # Ignore.
+ end
+
+ Thread.pass until reading_thread.status == 'sleep'
+
+ thread = Thread.new do
+ scheduler = Scheduler.new
+ Fiber.set_scheduler scheduler
+
+ Fiber.schedule do
+ i.close
+ end
+ end
+
+ thread.join
+ reading_thread.join
+
+ assert_instance_of IOError, error
+ assert_match(/closed/, error.message)
+ end
+ end
+
+ # Problematic on Windows.
+ def test_io_close_blocking_fiber
+ omit "Interrupting a io_wait read is not supported!" if RUBY_PLATFORM =~ /mswin|mingw/
+
+ with_socket_pair do |i, o|
+ error = nil
+
+ thread = Thread.new do
+ scheduler = Scheduler.new
+ Fiber.set_scheduler scheduler
+
+ Fiber.schedule do
+ begin
+ i.read
+ rescue => error
+ # Ignore.
+ end
+ end
+ end
+
+ Thread.pass until thread.status == 'sleep'
+
+ i.close
+
+ thread.join
+
+ assert_instance_of IOError, error
+ assert_match(/closed/, error.message)
+ end
+ end
+end