Feature #20102
closedIntroduce `Fiber#resuming?`
Description
There are some tricky edge cases when using Fibre#raise
and Fiber#kill
, e.g.
fiber = nil
killer = Fiber.new do
fiber.raise("Stop")
end
fiber = Fiber.new do
killer.resume
end
fiber.resume
# 4:in `raise': attempt to raise a resuming fiber (FiberError)
# 4:in `block in <main>'
Async has to deal with this edge case explicitly by rescuing the exception:
I'd like to avoid doing that and instead just ask "Can I kill/raise on this fiber right now?" which is determined by whether the fiber itself can be resumed or transferred to.
To address this, I'd like to introduce Fiber#resuming?
:
/*
* call-seq: fiber.resumed? -> true or false
*
* Whether the fiber is currently resumed.
*/
VALUE
rb_fiber_resuming_p(VALUE fiber_value)
{
struct rb_fiber_struct *fiber = fiber_ptr(fiber_value);
if (FIBER_TERMINATED_P(fiber)) return RUBY_Qfalse;
return RBOOL(fiber->resuming_fiber);
}
See the PR: https://github.com/ruby/ruby/pull/9382
Updated by jeremyevans0 (Jeremy Evans) 12 months ago
- Tracker changed from Bug to Feature
- Backport deleted (
3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN)
Updated by Eregon (Benoit Daloze) 12 months ago
Could you make it raise FiberError
if it's called on a Fiber of a different thread?
Because that's always racy (i.e. it might have changed by the time resuming?
returns) so it seems wrong to query that for a Fiber belonging to another thread.
Updated by ioquatix (Samuel Williams) 12 months ago
@Eregon (Benoit Daloze) I appreciate your input. I don't mind doing that, but isn't that the same for all methods on Fiber? In other words, the GVL provides a bit of a safety net.
Should we apply this model to other methods? Maybe we need to define what methods can be called safely from one thread or another.
What about if a user has a mutex to control access, or the fiber/thread is not actually running at the time of the call?
I assume there is a lot of historical context/implementation where such behaviour is just racy but nothing is done to protect it.
In other words, I feel like the problem you are trying to address spans almost all of Ruby's mutable state... tricky.
Updated by Eregon (Benoit Daloze) 12 months ago
ioquatix (Samuel Williams) wrote in #note-4:
@Eregon (Benoit Daloze) I appreciate your input. I don't mind doing that, but isn't that the same for all methods on Fiber?
It is, and many methods on Fiber are already not allowed to be called for Fibers belonging to other threads (e.g. resume/transfer/storage/...).
Since we are adding a new method, we might as well encourage correct usage and discourage incorrect usage (+ it means the state for resuming does not need to become volatile
which would be bad for performance).
In other words, the GVL provides a bit of a safety net.
It does not, the GVL could be released e.g. just after resuming?
is done but before the caller gets the value and handle it.
Updated by matz (Yukihiro Matsumoto) 11 months ago
It appears to me that the method you want is to determine if an exception can legitimately be sent to the fiber. I am not rejecting the addition of such a method, but in that case, I think the name resuming?
would be inappropriate. Any other name candidate?
Matz.
Updated by hsbt (Hiroshi SHIBATA) 9 months ago
- Status changed from Open to Assigned
Updated by ioquatix (Samuel Williams) 9 months ago
- Status changed from Assigned to Closed
I found a different way to solve this problem, which I think is better, so I'll open a new issue.
Updated by ioquatix (Samuel Williams) 9 months ago
- Related to Bug #20414: `Fiber#raise` should recurse to `resumed_fiber` rather than failing. added
Updated by ioquatix (Samuel Williams) 9 months ago
Here is the updated proposal: https://bugs.ruby-lang.org/issues/20414