diff options
author | Samuel Williams <samuel.williams@oriontransfer.co.nz> | 2021-06-14 17:56:53 +1200 |
---|---|---|
committer | nagachika <nagachika@ruby-lang.org> | 2021-09-26 20:49:54 +0900 |
commit | 5e9ec351044fb74f07f2a45a0dab1e226159b7e6 (patch) | |
tree | d88a0da7c222748f83792654eec867debd6624e7 /test | |
parent | 98ac62de5cb03efec0fb32684c61c0d4df692e5a (diff) |
Wake up join list within thread EC context. (#4471)
* Wake up join list within thread EC context.
* Consume items from join list so that they are not re-executed.
If `rb_fiber_scheduler_unblock` raises an exception, it can result in a
segfault if `rb_threadptr_join_list_wakeup` is not within a valid EC. This
change moves `rb_threadptr_join_list_wakeup` into the thread's top level EC
which initially caused an infinite loop because on exception will retry. We
explicitly remove items from the thread's join list to avoid this situation.
* Verify the required scheduler interface.
* Test several scheduler hooks methods with broken `unblock` implementation.
Diffstat (limited to 'test')
-rw-r--r-- | test/fiber/scheduler.rb | 8 | ||||
-rw-r--r-- | test/fiber/test_scheduler.rb | 18 | ||||
-rw-r--r-- | test/fiber/test_sleep.rb | 22 | ||||
-rw-r--r-- | test/fiber/test_thread.rb | 20 |
4 files changed, 66 insertions, 2 deletions
diff --git a/test/fiber/scheduler.rb b/test/fiber/scheduler.rb index b3c3eaff59..0553e386f5 100644 --- a/test/fiber/scheduler.rb +++ b/test/fiber/scheduler.rb @@ -188,3 +188,11 @@ class Scheduler return fiber end end + +class BrokenUnblockScheduler < Scheduler + def unblock(blocker, fiber) + super + + raise "Broken unblock!" + end +end diff --git a/test/fiber/test_scheduler.rb b/test/fiber/test_scheduler.rb index 72bde9fcc3..d1fb89d693 100644 --- a/test/fiber/test_scheduler.rb +++ b/test/fiber/test_scheduler.rb @@ -66,9 +66,23 @@ class TestFiberScheduler < Test::Unit::TestCase RUBY end - def test_optional_close + def test_minimal_interface + scheduler = Object.new + + def scheduler.block + end + + def scheduler.unblock + end + + def scheduler.io_wait + end + + def scheduler.kernel_sleep + end + thread = Thread.new do - Fiber.set_scheduler Object.new + Fiber.set_scheduler scheduler end thread.join diff --git a/test/fiber/test_sleep.rb b/test/fiber/test_sleep.rb index e882766345..844369740f 100644 --- a/test/fiber/test_sleep.rb +++ b/test/fiber/test_sleep.rb @@ -43,4 +43,26 @@ class TestFiberSleep < Test::Unit::TestCase assert_operator seconds, :>=, 2, "actual: %p" % seconds end + + def test_broken_sleep + thread = Thread.new do + Thread.current.report_on_exception = false + + scheduler = Scheduler.new + + def scheduler.kernel_sleep(duration = nil) + raise "Broken sleep!" + end + + Fiber.set_scheduler scheduler + + Fiber.schedule do + sleep 0 + end + end + + assert_raise(RuntimeError) do + thread.join + end + end end diff --git a/test/fiber/test_thread.rb b/test/fiber/test_thread.rb index 5fc80f0e6c..b7323d7237 100644 --- a/test/fiber/test_thread.rb +++ b/test/fiber/test_thread.rb @@ -42,4 +42,24 @@ class TestFiberThread < Test::Unit::TestCase assert_equal :done, thread.value end + + def test_broken_unblock + thread = Thread.new do + Thread.current.report_on_exception = false + + scheduler = BrokenUnblockScheduler.new + + Fiber.set_scheduler scheduler + + Fiber.schedule do + Thread.new{}.join + end + + scheduler.run + end + + assert_raise(RuntimeError) do + thread.join + end + end end |