Skip to content
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

When peeking via SIGQUIT, every 'require' causes an error #52

Open
zach opened this issue Jan 8, 2014 · 8 comments
Open

When peeking via SIGQUIT, every 'require' causes an error #52

zach opened this issue Jan 8, 2014 · 8 comments

Comments

@zach
Copy link

zach commented Jan 8, 2014

I have had poor luck with getting peek to work via Ctrl-\ since every require statement seems to cause an error, worst of all being those in Pry :before_session hooks and those from CodeRay autoloads. As a result, I never get to see the code I'm trying to peek at, nor can I explore the stack or the other stuff. I really like this functionality and would love to make this work, but if require doesn't work I don't understand how it ever did.

Here are some example sessions:

^\Preparing to peek via pry!
require 'pry-debugger' # Failed, saying: can't be called from trap context

Frame number: 0/44
Frame type: method
before_session hook failed: ThreadError: can't be called from trap context

(hangs)

^\Preparing to peek via pry!
require 'pry-debugger' # Failed, saying: can't be called from trap context
require 'pry-doc' # Failed, saying: can't be called from trap context
require 'pry-git' # Failed, saying: can't be called from trap context
require 'pry-rails' # Failed, saying: can't be called from trap context
require 'pry-remote' # Failed, saying: can't be called from trap context

Frame number: 0/2
Frame type: block
before_session hook failed: ThreadError: can't be called from trap context
/Users/zach/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/coderay-1.1.0/lib/coderay.rb:169:in `scan'
(see _pry_.hooks.errors to debug)
before_session hook failed: ThreadError: can't be called from trap context
/Users/zach/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/interception-0.3/lib/interception.rb:64:in `synchronize'
(see _pry_.hooks.errors to debug)
[1] (pry) main: 0> up
ThreadError: can't be called from trap context
from /Users/zach/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/coderay-1.1.0/lib/coderay.rb:169:in `scan'
[1] (pry) main: 0>

This is in Ruby 2.0 on OS X 10.9. Maybe there's something I don't have configured properly, but even a simple script that I break into with Ctrl-\ has this problem. I made a repo with this example (run main.rb and use Ctrl-\ or just run the test script and peek after it prints the first line of numbers):

https://github.com/zach/pry-rescue-peek-test

Why does this seem to work in other circumstances and yet I can't seem to make this work? Is this a Bundler-related issue?

@Incanus3
Copy link

+1
I get exactly the same errors when trying to rescue a hanging rspec test using rescue rspec and Ctrl-\ in ruby 2.1, pry-rescue 1.2.0.

@Incanus3
Copy link

I just did bundle update to pry-rescue 1.3.1 and interception 0.4. It's still failing, but the output changed a bit:

^\Preparing to peek via pry!
Error loading ./.pryrc: can't be called from trap context
/home/jakub/.rvm/gems/ruby-2.1.0@objednavky/gems/activesupport-4.0.1/lib/active_support/dependencies.rb:229:in `require'
require 'pry-doc' # Failed, saying: can't be called from trap context
require 'pry-docmore' # Failed, saying: can't be called from trap context
require 'pry-rails' # Failed, saying: can't be called from trap context

Frame number: 0/54
Frame type: method
before_session hook failed: RegexpError: empty char-class: /^define_singleton_method\(?\s*[:\"\'][]|^def\s*self\.[]/
/home/jakub/.rvm/gems/ruby-2.1.0@global/gems/pry-0.9.12.4/lib/pry/method.rb:182:in `singleton_method_definition?'
(see _pry_.hooks.errors to debug)
before_session hook failed: ThreadError: can't be called from trap context
/home/jakub/.rvm/gems/ruby-2.1.0@objednavky/gems/interception-0.4/lib/interception.rb:64:in `synchronize'
(see _pry_.hooks.errors to debug)

Not really sure what the last line means, but any command after this fails. Can provide more info if you tell me where to look.

@zach
Copy link
Author

zach commented Jan 24, 2014

I found what seems to be the root cause, which is that Ruby has a very limited ability to perform I/O (in this case, apparently including reading files via require) inside signal handlers in Ruby 2.0. In 1.9.x performing such actions could cause deadlock, so in 2.0 they are simply not allowed. Thanks to @mperham I was able to pick up on this quickly, since he wrote up his experience encountering this in Sidekiq:

http://www.mikeperham.com/2013/02/23/signal-handling-with-ruby/

There are some workarounds for libraries like Foreman (see ddollar/foreman#332 for their pipe-based solution), but they don't have to interrupt arbitrary code in its current execution state. I don't know enough about the details of pry and ruby execution state to say whether there might be a workaround for pry-rescue.

This looks like a tough one. Any ideas?

@ConradIrwin
Copy link
Owner

Is there anything we can do in a signal handler to escape? e.g. Signal.trap{ <capture bindings>; Thread.new{ <go wild> }.join }

@zach
Copy link
Author

zach commented May 19, 2014

Update: Guard has tackled this issue as well using a separate thread. I don't think it has access to the current binding, but that's a lot to ask. guard/guard#571

@elia
Copy link

elia commented Jun 13, 2014

As done by @mperham the trap should just add signals to a queue (an array or, better, a queue*) and then you can keep a loop inside a thread that will pop from the event queue.

* the queue is better because avoids using sleep by using the blocking #pop. Using #sleep of course is fine in sidekiq but not in a user facing app

@elia
Copy link

elia commented Jun 13, 2014

@stdedos
Copy link

stdedos commented Jun 25, 2018

Similar backtrace:

[5] pry(Timeout)> yield(0)
^\Preparing to peek via pry!
ThreadError: can't be called from trap context
from /data/ruby/lib/ruby/2.4.0/monitor.rb:187:in `lock'
[6] pry(Timeout)> bt
=> nil
[7] pry(Timeout)> backtrace
--> #0  #<Class:Timeout>.timeout(sec#Float, klass#NilClass, message#NilClass) at /spool/ruby/lib/ruby/2.4.0/timeout.rb:77

And the full trace:

#<ThreadError: can't be called from trap context>
/data/ruby/lib/ruby/2.4.0/monitor.rb:187:in `lock'
/data/ruby/lib/ruby/2.4.0/monitor.rb:187:in `mon_enter'
/data/ruby/lib/ruby/site_ruby/2.4.0/rubygems/core_ext/kernel_require.rb:40:in `require'
/data/ruby/lib/ruby/gems/2.4.0/gems/pry-rescue-1.4.5/lib/pry-rescue/peek.rb:10:in `peek!'
(and then mixed code with gems: event-machine, aspector, timeout)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants