From: "ko1 (Koichi Sasada) via ruby-core" Date: 2023-03-12T15:00:29+00:00 Subject: [ruby-core:112856] [Ruby master Bug#19473] can't be called from trap context (ThreadError) is too limiting Issue #19473 has been updated by ko1 (Koichi Sasada). Eregon (Benoit Daloze) wrote in #note-8: > Right, like I mentioned above. > But the deadlock might not happen (or even cannot happen for some cases I mentioned above), and then CRuby fails needlessly. > If the deadlock does happen, then we would get this error: `deadlock; recursive locking (ThreadError)`. Which means the program doesn't hang and there is a stacktrace and it shows relevant information which is useful to fix it. My understandings are: (1) It is hard to detect such deadlock risk because such errors occur with with very low frequency. (2) It is hard to expect that the Mutex users care about signal handlers. (3) It is hard to modify fixing with signal handlers. So I think current limitation makes sense. >> akr had proposed that if someone want to use such case, how about to make a thread in a trap handler for workaround. I think it is reasonable. > I cannot really use that here, or I would need an efficient way to know I'm in a trap handler (I suppose I could catch the can't be called from trap context (ThreadError) but that's really ugly and likely quite slow). > Because Timeout doesn't define the trap handler, the user does. > And asking every user to workaround like that doesn't seem good, that actually creates more threads than a single signal-handling thread created by Ruby. akr's idea is not about Timeout library, but for Timeout users in trap handers. If someone wants to use Timeout (or other complex/thread-safety needed code), making a thread like `trap(...){Thread.new{ ... }}` seems feasible workaround. ---------------------------------------- Bug #19473: can't be called from trap context (ThreadError) is too limiting https://bugs.ruby-lang.org/issues/19473#change-102367 * Author: Eregon (Benoit Daloze) * Status: Open * Priority: Normal * ruby -v: ruby 3.2.1 (2023-02-08 revision 31819e82c8) [x86_64-linux] * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- Simple reproducer: ``` $ ruby -ve 'm=Mutex.new; trap(:HUP) { m.synchronize { p :OK } }; Process.kill :HUP, Process.pid; sleep 0.1' ruby 3.2.1 (2023-02-08 revision 31819e82c8) [x86_64-linux] -e:1:in `synchronize': can't be called from trap context (ThreadError) from -e:1:in `block in
' from -e:1:in `kill' from -e:1:in `
' ``` Expected behavior: ``` $ ruby -ve 'm=Mutex.new; trap(:HUP) { m.synchronize { p :OK } }; Process.kill :HUP, Process.pid; sleep 0.1' truffleruby 22.3.1, like ruby 3.0.3, GraalVM CE Native [x86_64-linux] :OK $ ruby -ve 'm=Mutex.new; trap(:HUP) { m.synchronize { p :OK } }; Process.kill :HUP, Process.pid; sleep 0.1' jruby 9.4.0.0 (3.1.0) 2022-11-23 95c0ec159f OpenJDK 64-Bit Server VM 17.0.6+10 on 17.0.6+10 +jit [x86_64-linux] :OK ``` This exception is highly problematic, for instance it breaks `Timeout.timeout` in `trap`: https://github.com/ruby/timeout/issues/17#issuecomment-1142035939 I suppose this behavior is because *sometimes* it's problematic to lock a Mutex in trap, e.g., if it's already locked by the main thread/fiber. But that would otherwise already raise `deadlock; recursive locking (ThreadError)`, so there is no point to fail early. And that's just one case, not all, so we should not always raise an exception. There seems to be no valid reason to prevent *all* `Mutex#synchronize` in `trap`. After all, if the Mutex for instance is only used in `trap`, it's well-defined AFAIK. For instance a given trap handler does not seem executed concurrently: ``` $ ruby -ve 'trap(:HUP) { puts "in trap\n"+caller.join("\n")+"\n\n"; sleep 0.1 }; pid = Process.pid; Process.wait fork { 20.times { Process.kill :HUP, pid } }; sleep 1' ruby 3.2.1 (2023-02-08 revision 31819e82c8) [x86_64-linux] in trap -e:1:in `wait' -e:1:in `
' in trap -e:1:in `wait' -e:1:in `
' in trap -e:1:in `wait' -e:1:in `
' in trap -e:1:in `wait' -e:1:in `
' in trap -e:1:in `wait' -e:1:in `
' in trap -e:1:in `wait' -e:1:in `
' ``` And if the trap handler using the Mutex is never called while the Mutex is held by the main thread/fiber, there is also no problem. -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/