-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Timeout cannot be called in a trap handler as of 0.3.0 #17
Comments
I don't think there is a way to fix this in this gem. Lines 83 to 97 in 01554f1
An example race without it is we risk in interrupt to read a stale @done (or read it just before it's set by finished ) and could @thread.raise after the thread has completed the timeout block, which of course would be a very bad bug.
5e0d8e1 just uses it early but wouldn't change anything, it's used anyway in It could be a simple AtomicBoolean instead of a Mutex (with CAS + read), but there is no such thing in Ruby core or stdlib (only in concurrent-ruby, but somehow AtomicBoolean doesn't seem to have a CAS, only AtomicReference). There are also 2 other Mutex instances used in Timeout (TIMEOUT_THREAD_MUTEX, QUEUE_MUTEX).
FWIW on CRuby, both Mutex#synchronize and Monitor#synchronize
|
We're using |
It's only a regression on CRuby, so please file an issue to https://bugs.ruby-lang.org/. The change itself (#15) avoids creating one thread per call and has huge performance advantages so we will not revert it just for this. |
Already said above, but to be clear there is no need to rewrite the code. |
Just to summarize the discussion as I understand it. The new implementation introduced in #15 uses fewer resources and performs better than the previous version (which is awesome) but requires synchronization to work. There is no way to address the regression because Ruby doesn't have an API for atomic operations (read, write, cas, etc...). A more general solution is to ask the CRuby team to make CRuby act the same way as JRuby. We'll plan to rework our code to pull the Timeout out of the trap handler and into the main thread instead. |
That makes sense, such cleanup should probably be part of |
If you can't synchronize in the trap, perhaps it should just use the old logic that spins up an interrupt thread. Obviously that worked fine before. The new logic is much more efficient, but has introduced this and other issues (#21) so I think we need to provide a multi-faceted solution. |
CRuby issue: https://bugs.ruby-lang.org/issues/19473 |
Because there is no such restriction, there is a low-reproducibility race condition bug in timeout 0.3.2 with JRuby/TruffleRuby. I confirmed it by the following procedure.
require "timeout"
trap(:INT) do
Timeout.timeout(1) do
p :ok
end
end
Timeout.timeout(1) do
sleep
end
CRuby prohibits mutex lock in traps to prevent such a race condition issue. @eregon Do you think who should address this issue? timeout? Or end users? And how? Cc/ @headius |
@mame I think that can be addressed by A Monitor instead of Mutex here wouldn't fully work because then there could be two threads created (if the trap handlers runs between We would need a AtomicReference or AtomicBoolean here ideally, but Ruby core provides no such thing. That could be enough on its own in this very specific case, because if two threads get into |
This doesn't work on CRuby for the example in the description, due to the too strict limitation.
|
|
As of Timeout 0.3.0 you can no longer use
Timeout
in a signal trap handler due toMutex#synchronize
not being callable inside a trap context. I haven't done a git bisect but I believe this was broken in 5e0d8e1 due to the addition of a mutex on@done
.This works fine with
0.2.0
.Exception
The text was updated successfully, but these errors were encountered: