summaryrefslogtreecommitdiff
path: root/test/ruby
diff options
context:
space:
mode:
authornicholas a. evans <nicholas.evans@gmail.com>2021-02-21 16:33:11 -0500
committerGitHub <noreply@github.com>2021-02-22 10:33:11 +1300
commit3ee4fa9491d0b2b5fb40deea8e93e797924de789 (patch)
tree8bc76a96a94e995d8c786870041bad2b0f0cdbec /test/ruby
parentaeac4ddcc0de536c0ecdea29e01dd2505e32f6ae (diff)
Send :fiber_switch event for almost every fiber_switch (#4207)
With this patch, TracePoint receives a `:fiber_switch` event for _almost_ every fiber switch. Previously, it would not be sent when an exception was going to be raised. Now the event should only be blockable by an interrupt (including `Thread#raise`) or a fatal error. Additionally, interrupts will now be checked on the return fiber _before_ re-raising the terminating unhandled exception. And a fiber that terminates with an unhandled exception no longer creates a pending interrupt on its thread. The exception will be raised in the return fiber the same way as `Fiber#raise`: using `cont.value` with `cont.argc == -1` I moved `rb_exc_raise` from `fiber_store` to the end of `fiber_switch` after _all_ of the other cleanup code: `fiber_stack_release`, `th->blocking` increment, `RUBY_VM_CHECK_INTS`, and `EXEC_EVENT_HOOK`. It seems to me that skipping those other cleanup steps may have also resulted in other bugs.
Notes
Notes: Merged-By: ioquatix <samuel@codeotaku.com>
Diffstat (limited to 'test/ruby')
-rw-r--r--test/ruby/test_settracefunc.rb62
1 files changed, 62 insertions, 0 deletions
diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb
index 1d16b2e154..fdd5bd2dce 100644
--- a/test/ruby/test_settracefunc.rb
+++ b/test/ruby/test_settracefunc.rb
@@ -1593,6 +1593,33 @@ class TestSetTraceFunc < Test::Unit::TestCase
assert_equal ev, :fiber_switch
}
+ # test for raise into resumable fiber
+ evs = []
+ f = nil
+ TracePoint.new(:raise, :fiber_switch){|tp|
+ next unless target_thread?
+ evs << [tp.event, Fiber.current]
+ }.enable{
+ f = Fiber.new{
+ Fiber.yield # will raise
+ Fiber.yield # unreachable
+ }
+ begin
+ f.resume
+ f.raise StopIteration
+ rescue StopIteration
+ evs << :rescued
+ end
+ }
+ assert_equal [:fiber_switch, f], evs[0], "initial resume"
+ assert_equal [:fiber_switch, Fiber.current], evs[1], "Fiber.yield"
+ assert_equal [:fiber_switch, f], evs[2], "fiber.raise"
+ assert_equal [:raise, f], evs[3], "fiber.raise"
+ assert_equal [:fiber_switch, Fiber.current], evs[4], "terminated with raise"
+ assert_equal [:raise, Fiber.current], evs[5], "terminated with raise"
+ assert_equal :rescued, evs[6]
+ assert_equal 7, evs.size
+
# test for transfer
evs = []
TracePoint.new(:fiber_switch){|tp|
@@ -1615,6 +1642,41 @@ class TestSetTraceFunc < Test::Unit::TestCase
evs.each{|ev|
assert_equal ev, :fiber_switch
}
+
+ # test for raise and from transferring fibers
+ evs = []
+ f1 = f2 = nil
+ TracePoint.new(:raise, :fiber_switch){|tp|
+ next unless target_thread?
+ evs << [tp.event, Fiber.current]
+ }.enable{
+ f1 = Fiber.new{
+ f2.transfer
+ f2.raise ScriptError
+ Fiber.yield :ok
+ }
+ f2 = Fiber.new{
+ f1.transfer
+ f1.transfer
+ }
+ begin
+ f1.resume
+ rescue ScriptError
+ evs << :rescued
+ end
+ }
+ assert_equal [:fiber_switch, f1], evs[0], "initial resume"
+ assert_equal [:fiber_switch, f2], evs[1], "f2.transfer"
+ assert_equal [:fiber_switch, f1], evs[2], "f1.transfer"
+ assert_equal [:fiber_switch, f2], evs[3], "f2.raise ScriptError"
+ assert_equal [:raise, f2], evs[4], "f2.raise ScriptError"
+ assert_equal [:fiber_switch, f1], evs[5], "f2 unhandled exception"
+ assert_equal [:raise, f1], evs[6], "f2 unhandled exception"
+ assert_equal [:fiber_switch, Fiber.current], evs[7], "f1 unhandled exception"
+ assert_equal [:raise, Fiber.current], evs[8], "f1 unhandled exception"
+ assert_equal :rescued, evs[9], "rescued everything"
+ assert_equal 10, evs.size
+
end
def test_tracepoint_callee_id