From 9d2a5c014b1d0bc5321683d8cdb7285c79dc8f82 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 28 Mar 2023 18:05:45 +0900 Subject: [PATCH] restart all threads on eval When a thread keeps a lock, and REPL runs a code which needs the lock, other threads should make a progress to release the lock. fix https://github.com/ruby/debug/issues/877 --- lib/debug/session.rb | 17 +++++++++++------ lib/debug/thread_client.rb | 10 +++++++++- test/console/eval_test.rb | 26 ++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index b2ee5e50a..298eefddd 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -343,7 +343,7 @@ def process_event evt opt = ev_args[3] add_tracer ObjectTracer.new(@ui, obj_id, obj_inspect, **opt) else - # ignore + stop_all_threads end wait_command_loop @@ -900,13 +900,13 @@ def register_default_command # * `p ` # * Evaluate like `p ` on the current frame. register_command 'p' do |arg| - request_tc [:eval, :p, arg.to_s] + request_eval :p, arg.to_s end # * `pp ` # * Evaluate like `pp ` on the current frame. register_command 'pp' do |arg| - request_tc [:eval, :pp, arg.to_s] + request_eval :pp, arg.to_s end # * `eval ` @@ -917,7 +917,7 @@ def register_default_command @ui.puts "\nTo evaluate the variable `#{cmd}`, use `pp #{cmd}` instead." :retry else - request_tc [:eval, :call, arg] + request_eval :call, arg end end @@ -928,7 +928,7 @@ def register_default_command @ui.puts "not supported on the remote console." :retry end - request_tc [:eval, :irb] + request_eval :irb, nil end ### Trace @@ -1148,7 +1148,7 @@ def process_command line @repl_prev_line = nil check_unsafe - request_tc [:eval, :pp, line] + request_eval :pp, line end rescue Interrupt @@ -1164,6 +1164,11 @@ def process_command line return :retry end + def request_eval type, src + restart_all_threads + request_tc [:eval, type, src] + end + def step_command type, arg if type == :until leave_subsession [:step, type, arg] diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index cd79a3205..cbecdf54d 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -1230,7 +1230,15 @@ def wait_next_action_ rescue SuspendReplay, SystemExit, Interrupt raise rescue Exception => e - pp ["DEBUGGER Exception: #{__FILE__}:#{__LINE__}", e, e.backtrace] + STDERR.puts e.cause.inspect + STDERR.puts e.inspect + Thread.list.each{|th| + STDERR.puts "@@@ #{th}" + th.backtrace.each{|b| + STDERR.puts " > #{b}" + } + } + p ["DEBUGGER Exception: #{__FILE__}:#{__LINE__}", e, e.backtrace] raise ensure @returning = false diff --git a/test/console/eval_test.rb b/test/console/eval_test.rb index 6b066b157..ff710cd90 100644 --- a/test/console/eval_test.rb +++ b/test/console/eval_test.rb @@ -35,4 +35,30 @@ def test_eval_evaluates_computation_and_assignment end end end + + class EvalThreadTest < ConsoleTestCase + def program + <<~RUBY + 1| th0 = Thread.new{sleep} + 2| m = Mutex.new; q = Queue.new + 3| th1 = Thread.new do + 4| m.lock; q << true + 5| sleep 1 + 6| m.unlock + 7| end + 8| q.pop # wait for locking + 9| p :ok + RUBY + end + + def test_eval_with_threads + debug_code program do + type 'b 9' + type 'c' + type 'm.lock.nil?' + assert_line_text 'false' + type 'c' + end + end + end end