Last active
October 27, 2020 05:03
-
-
Save nevans/4d9a0e591e06ced2e2691a363452da9b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
require "fiber" # needed for transfer | |
RootFiberException = Class.new(Exception) | |
RootFiberTestSignal = Class.new(RootFiberException) | |
# Warning: this is only safe to call from the root fiber for a thread. | |
# Unfortunately, your code may not know if it is in the root fiber. This will | |
# raise an exception in the root fiber of the current thread. If you are in the | |
# root fiber, it will also catch that exception. If not, the root fiber will | |
# most likely crash, bringing the thread down with it! | |
# | |
# The trick is that, unlike Fiber#resume, Fiber#transfer doesn't set a | |
# "return_fiber" pointer. So when the fiber returns (or yields or raises), it | |
# doesn't necessarily go back the the fiber that created it or the fiber that | |
# transfered into it. Instead, it transfers to the root fiber. | |
def check_in_root_fiber! | |
msg = "Another fiber raised this exception (#{rand})" | |
test_fiber = Fiber.new { raise RootFiberTestSignal, msg; } | |
test_fiber.transfer # th | |
rescue RootFiberTestSignal => ex | |
raise ex unless ex.message == msg | |
true | |
else | |
raise RootFiberException, "in_root_fiber? was called from a non-root fiber" | |
end | |
check_in_root_fiber! # => true | |
nonroot = Fiber.new do | |
Fiber.new do | |
Fiber.new do | |
Fiber.new do | |
check_in_root_fiber! | |
end.resume | |
end.resume | |
end.resume | |
end | |
nonroot.resume | |
# ~> RootFiberTestSignal | |
# ~> Another fiber raised this exception (0.06201568006087321) | |
# ~> | |
# ~> /tmp/seeing_is_believing_temp_dir20201027-2846277-176v8hz/program.rb:18:in `block in check_in_root_fiber!' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment