-
-
Notifications
You must be signed in to change notification settings - Fork 925
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
Lock is not released at Kernel.require when Gem.try_activate throws RuntimeException #3652
Comments
I think that improving lock code at |
Serializes access to Gem.loaded_specs to mitigate probability of possible deadlock of jruby/jruby#3652.
Serializes access to Gem.loaded_specs to mitigate probability of possible deadlock of jruby/jruby#3652.
So is this a bug in RubyGems then? The locks in question are in It appears that in a very recent RubyGems on our |
Here's a patch I think will work. @frsyuki if you could test this patch, all that's left is reporting to RubyGems and getting a release we can use. diff --git a/lib/ruby/stdlib/rubygems/core_ext/kernel_require.rb b/lib/ruby/stdlib/rubygems/core_ext/kernel_require.rb
index f9b67ea..accbf53 100644
--- a/lib/ruby/stdlib/rubygems/core_ext/kernel_require.rb
+++ b/lib/ruby/stdlib/rubygems/core_ext/kernel_require.rb
@@ -120,14 +120,17 @@ module Kernel
rescue LoadError => load_error
RUBYGEMS_ACTIVATION_MONITOR.enter
- if load_error.message.start_with?("Could not find") or
- (load_error.message.end_with?(path) and Gem.try_activate(path)) then
- RUBYGEMS_ACTIVATION_MONITOR.exit
- return gem_original_require(path)
- else
+ begin
+ if load_error.message.start_with?("Could not find") or
+ (load_error.message.end_with?(path) and Gem.try_activate(path)) then
+ require_again = true
+ end
+ ensure
RUBYGEMS_ACTIVATION_MONITOR.exit
end
+ return gem_original_require(path) if require_again
+
raise load_error
end |
@headius thank you. I'll test that patch. |
@headius I tried above patch for 1 week with @muga. Deadlock is not happening at least for now. Thank you! |
I think we should move this discussion to a RubyGems issue. This appears to be their bug. |
See jruby/jruby#3652. I'm not sure how best to test this; the original report has a rather complicated env setup not suitable for RG test suite. There may be locking required around the iteration of Gem.loaded_specs, in case parallel gem activation is attempting to mutate that structure concurrently.
I have filed rubygems/rubygems#1538. We'll leave this open until we can update 1.7 and 9k to the fixed version. |
Ensure we unlock the monitor even if try_activate throws. # Description: Not all paths ensured the monitor was unlocked. Specifically `try_activat`e could throw here (possibly exposing an internal bug, but still) and leave the monitor locked, preventing any future requires from entering the Gem require. This patch modifies the `try_activate` logic to always unlock the monitor, success or fail. See jruby/jruby#3652. I'm not sure how best to test this; the original report has a rather complicated env setup not suitable for RG test suite. There may be locking required around the iteration of Gem.loaded_specs, in case parallel gem activation is attempting to mutate that structure concurrently. # Tasks: - [x] Describe the problem / feature - [x] Write tests I'm not sure how to write a test for this. We'd have to get `try_activate` to raise. - [x] Write code to solve the problem - [ ] Get code review from coworkers / friends - [x] [Squash commits](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html) I will abide by the [code of conduct](https://github.com/rubygems/rubygems/blob/master/CODE_OF_CONDUCT.md).
Ensure we unlock the monitor even if try_activate throws. # Description: Not all paths ensured the monitor was unlocked. Specifically `try_activat`e could throw here (possibly exposing an internal bug, but still) and leave the monitor locked, preventing any future requires from entering the Gem require. This patch modifies the `try_activate` logic to always unlock the monitor, success or fail. See jruby/jruby#3652. I'm not sure how best to test this; the original report has a rather complicated env setup not suitable for RG test suite. There may be locking required around the iteration of Gem.loaded_specs, in case parallel gem activation is attempting to mutate that structure concurrently. # Tasks: - [x] Describe the problem / feature - [x] Write tests I'm not sure how to write a test for this. We'd have to get `try_activate` to raise. - [x] Write code to solve the problem - [ ] Get code review from coworkers / friends - [x] [Squash commits](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html) I will abide by the [code of conduct](https://github.com/rubygems/rubygems/blob/master/CODE_OF_CONDUCT.md).
Ensure we unlock the monitor even if try_activate throws. # Description: Not all paths ensured the monitor was unlocked. Specifically `try_activat`e could throw here (possibly exposing an internal bug, but still) and leave the monitor locked, preventing any future requires from entering the Gem require. This patch modifies the `try_activate` logic to always unlock the monitor, success or fail. See jruby/jruby#3652. I'm not sure how best to test this; the original report has a rather complicated env setup not suitable for RG test suite. There may be locking required around the iteration of Gem.loaded_specs, in case parallel gem activation is attempting to mutate that structure concurrently. # Tasks: - [x] Describe the problem / feature - [x] Write tests I'm not sure how to write a test for this. We'd have to get `try_activate` to raise. - [x] Write code to solve the problem - [ ] Get code review from coworkers / friends - [x] [Squash commits](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html) I will abide by the [code of conduct](https://github.com/rubygems/rubygems/blob/master/CODE_OF_CONDUCT.md).
Ensure we unlock the monitor even if try_activate throws. # Description: Not all paths ensured the monitor was unlocked. Specifically `try_activat`e could throw here (possibly exposing an internal bug, but still) and leave the monitor locked, preventing any future requires from entering the Gem require. This patch modifies the `try_activate` logic to always unlock the monitor, success or fail. See jruby/jruby#3652. I'm not sure how best to test this; the original report has a rather complicated env setup not suitable for RG test suite. There may be locking required around the iteration of Gem.loaded_specs, in case parallel gem activation is attempting to mutate that structure concurrently. # Tasks: - [x] Describe the problem / feature - [x] Write tests I'm not sure how to write a test for this. We'd have to get `try_activate` to raise. - [x] Write code to solve the problem - [ ] Get code review from coworkers / friends - [x] [Squash commits](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html) I will abide by the [code of conduct](https://github.com/rubygems/rubygems/blob/master/CODE_OF_CONDUCT.md).
See jruby/jruby#3652. I'm not sure how best to test this; the original report has a rather complicated env setup not suitable for RG test suite. There may be locking required around the iteration of Gem.loaded_specs, in case parallel gem activation is attempting to mutate that structure concurrently.
Ensure we unlock the monitor even if try_activate throws. # Description: Not all paths ensured the monitor was unlocked. Specifically `try_activat`e could throw here (possibly exposing an internal bug, but still) and leave the monitor locked, preventing any future requires from entering the Gem require. This patch modifies the `try_activate` logic to always unlock the monitor, success or fail. See jruby/jruby#3652. I'm not sure how best to test this; the original report has a rather complicated env setup not suitable for RG test suite. There may be locking required around the iteration of Gem.loaded_specs, in case parallel gem activation is attempting to mutate that structure concurrently. # Tasks: - [x] Describe the problem / feature - [x] Write tests I'm not sure how to write a test for this. We'd have to get `try_activate` to raise. - [x] Write code to solve the problem - [ ] Get code review from coworkers / friends - [x] [Squash commits](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html) I will abide by the [code of conduct](https://github.com/rubygems/rubygems/blob/master/CODE_OF_CONDUCT.md).
Fixed by RG 2.6.2 in fb71835. See rubygems/rubygems#1538 for details. |
Issues
require
defined atstdlib/rubygems/core_ext/kernel_require.rb
locks a monitor but doesn't release it ifGem.try_active
throws a RuntimeException.Gem.active
with "can't add a new key into hash during iteration" message if another thread is iteratingGem.loaded_specs
.Details
My application is using JRuby. I found that many threads are blocked at the same method (full stacktrace is at https://gist.github.com/frsyuki/17601f3b1483adbd6019#file-sigdump-3892-log ):
I got this Ruby stacktrace using sigdump.
Then, I found following error happened 6 hours ago (full stacktrace is at https://gist.github.com/frsyuki/17601f3b1483adbd6019#file-error1-log-L70 )
This error happened at lib/ruby/stdlib/rubygems/core_ext/kernel_require.rb:126. It assumes that
Gem.try_activate
doesn't throw exception and doesn't release acquired lock if an error happened.I'm not sure which thread was iterating
Gem.loaded_specs
object. But it seems a public API which could be called by arbitrary code.Environment
The text was updated successfully, but these errors were encountered: