[ruby-dev:11846] [Patch] debug.rb: Re: Debugging thread
From:
"NAKAMURA, Hiroshi" <nakahiro@...>
Date:
2000-12-25 07:17:40 UTC
List:
ruby-dev #11846
なひです。
> From: Yukihiro Matsumoto
> Sent: Friday, December 08, 2000 10:22 AM
> |> |1-a. いずれかのthreadがbpなどで停止すると、全threadが止まる。
> |> |1-b. いずれかのthreadがbpなどで停止すると、そのthreadのみが止まる。
> |> |2. thread stopすると、指定されたthreadが止まる。
> |> |3. thread resumeすると、指定されたthreadが再開する。
> |> |
> |> |とかですかね?ちょっと排他制御が難しくなりそう。。。
> |>
> |> 2,3はその通りです。1は1-bが望ましいと思ってます。
> |
> |A) 1-aが欲しいシチュエーションはどうしましょうか。
> |「何か起こった時」の状態を検査したい場合、
> |動きつづけられると困る場合もあると思います。
>
> ああ、そうか。たとえば1-aで、次の再開(nとかcとか)で全部が動
> きだすとかが可能であればその方が良いかもしれませんね。
そのように変更しました。^Cやbpでは、全スレッドが止まります。
n/s/cでは全スレッドを再開します。
デバッグコマンドとして、thread resume ##、thread stop ##で、
指定したスレッドの再開/停止をします。
デバッグ中のカレントスレッドは再開しません。
従来、thread stop ##は、thread ##と同じく、「カレントスレッドを
再開し、指定したスレッドを止める」すなわちスレッドの切り替えでしたが、
上記のように意味が変わっていますのでご注意ください。
trace on/offは、[ruby-dev:11785]のtracer.rbへのpatchを当てないと動きません。
1.6.2に間に合わないだろうことは承知してます。
patchを出すのが遅すぎました。動作確認に時間がかかってしまいました。
って書いてるところで[ruby-list:26846]が届きました。^^;
--- /usr/local/lib/ruby/1.6/debug.rb Sun Oct 22 14:11:28 2000
+++ ./debug.rb Mon Dec 25 16:08:20 2000
@@ -92,4 +92,5 @@ class DEBUGGER__
@trace = false
@catch = "StandardError"
+ @suspend_next = false
end
@@ -98,14 +99,45 @@ class DEBUGGER__
end
+ def suspend
+ @suspend_next = true
+ end
+
+ def check_suspend
+ while (Thread.critical = true; @suspend_next)
+ waiting.push Thread.current
+ @suspend_next = false
+ Thread.stop
+ end
+ Thread.critical = false
+ end
+
+ def trace?
+ @trace
+ end
+
+ def set_trace(arg)
+ @trace = arg
+ end
+
def stdout
DEBUGGER__.stdout
end
+
def break_points
DEBUGGER__.break_points
end
+
def display
DEBUGGER__.display
end
+ def waiting
+ DEBUGGER__.waiting
+ end
+
+ def set_trace_all(arg)
+ DEBUGGER__.set_trace(arg)
+ end
+
def debug_eval(str, binding)
begin
@@ -219,5 +251,6 @@ class DEBUGGER__
@frames[0] = [binding, file, line, id]
display_expressions(binding)
- while input = readline("(rdb:%d) "%thnum(), true)
+ prompt = true
+ while prompt and input = readline("(rdb:%d) "%thnum(), true)
catch(:debug_error) do
if input == ""
@@ -229,16 +262,22 @@ class DEBUGGER__
case input
- when /^\s*tr(?:ace)?(?:\s+(on|off))?$/
- if defined?( $1 )
+ when /^\s*tr(?:ace)?(?:\s+(on|off))?(?:\s+(all))?$/
+ if defined?( $2 )
+ if $1 == 'on'
+ set_trace_all true
+ else
+ set_trace_all false
+ end
+ elsif defined?( $1 )
if $1 == 'on'
- @trace = true
+ set_trace true
else
- @trace = false
+ set_trace false
end
end
- if @trace
- stdout.print "Trace on\n"
+ if trace?
+ stdout.print "Trace on.\n"
else
- stdout.print "Trace off\n"
+ stdout.print "Trace off.\n"
end
@@ -337,6 +376,5 @@ class DEBUGGER__
when /^\s*c(?:ont)?$/
- MUTEX.unlock
- return
+ prompt = false
when /^\s*s(?:tep)?(?:\s+(\d+))?$/
@@ -347,5 +385,5 @@ class DEBUGGER__
end
@stop_next = lev
- return
+ prompt = false
when /^\s*n(?:ext)?(?:\s+(\d+))?$/
@@ -357,5 +395,5 @@ class DEBUGGER__
@stop_next = lev
@no_step = @frames.size - frame_pos
- return
+ prompt = false
when /^\s*w(?:here)?$/, /^\s*f(?:rame)?$/
@@ -418,6 +456,5 @@ class DEBUGGER__
@finish_pos = @frames.size - frame_pos
frame_pos = 0
- MUTEX.unlock
- return
+ prompt = false
end
@@ -441,6 +478,8 @@ class DEBUGGER__
when /^\s*q(?:uit)?$/
- input = readline("really quit? (y/n) ", false)
- exit if input == "y"
+ input = readline("Really quit? (y/n) ", false)
+ if input == "y"
+ exit! # exit -> exit!: No graceful way to stop threads...
+ end
when /^\s*v(?:ar)?\s+/
@@ -452,6 +491,5 @@ class DEBUGGER__
when /^\s*th(?:read)?\s+/
if DEBUGGER__.debug_thread_info($', binding) == :cont
- MUTEX.unlock
- return
+ prompt = false
end
@@ -468,4 +506,6 @@ class DEBUGGER__
end
end
+ MUTEX.unlock
+ DEBUGGER__.resume_all_thread
end
@@ -493,5 +533,6 @@ Commands
down[ nn] move to lower frame
fin[ish] return to outer frame
- tr[ace][ (on|off)] set trace mode
+ tr[ace] (on|off) set trace mode of current thread
+ tr[ace] (on|off) all set trace mode of all threads
q[uit] exit from debugger
v[ar] g[lobal] show global variables
@@ -502,9 +543,8 @@ Commands
m[ethod] <class|module> show instance methods of class or module
th[read] l[ist] list all threads
- th[read] c[ur[rent]] show current threads
- th[read] <nnn> stop thread nnn
- th[read] stop <nnn> alias for th[read] <nnn>
- th[read] c[ur[rent]] <nnn> alias for th[read] <nnn>
- th[read] resume <nnn> run thread nnn
+ th[read] c[ur[rent]] show current thread
+ th[read] [sw[itch]] <nnn> switch thread context to nnn
+ th[read] stop <nnn> stop thread nnn
+ th[read] resume <nnn> resume thread nnn
p expression evaluate expression and print its value
h[elp] print this help
@@ -588,5 +628,5 @@ EOHELP
def check_break_points(file, pos, binding, id)
- MUTEX.lock # Stop all threads before 'line' and 'call'.
+ return false if break_points.empty?
file = File.basename(file)
n = 1
@@ -605,5 +645,4 @@ EOHELP
n += 1
end
- MUTEX.unlock
return false
end
@@ -617,5 +656,4 @@ EOHELP
if @catch and ($!.type.ancestors.find { |e| e.to_s == @catch })
- MUTEX.lock
fs = @frames.size
tb = caller(0)[-fs..-1]
@@ -625,4 +663,5 @@ EOHELP
end
end
+ DEBUGGER__.suspend_all_thread
debug_command(file, line, id, binding)
end
@@ -630,5 +669,6 @@ EOHELP
def trace_func(event, file, line, id, binding, klass)
- Tracer.trace_func(event, file, line, id, binding) if @trace
+ Tracer.trace_func(event, file, line, id, binding, klass) if trace?
+ DEBUGGER__.context(Thread.current).check_suspend
@file = file
@line = line
@@ -648,4 +688,5 @@ EOHELP
else
@no_step = nil
+ DEBUGGER__.suspend_all_thread
debug_command(file, line, id, binding)
@last = [file, line]
@@ -657,4 +698,5 @@ EOHELP
if check_break_points(file, id.id2name, binding, id) or
check_break_points(klass.to_s, id.id2name, binding, id)
+ DEBUGGER__.suspend_all_thread
debug_command(file, line, id, binding)
end
@@ -683,6 +725,5 @@ EOHELP
end
- trap("INT") { DEBUGGER__.interrupt }
-# $DEBUG = true
+ trap("INT") { DEBUGGER__.interrupt }
@last_thread = Thread::main
@max_thread = 1
@@ -690,4 +731,5 @@ EOHELP
@break_points = []
@display = []
+ @waiting = []
@stdout = STDOUT
@@ -696,4 +738,5 @@ EOHELP
@stdout
end
+
def stdout=(s)
@stdout = s
@@ -708,8 +751,44 @@ EOHELP
end
+ def waiting
+ @waiting
+ end
+
+ def set_trace( arg )
+ Thread.critical = true
+ make_thread_list
+ for th in @thread_list
+ context(th[0]).set_trace arg
+ end
+ Thread.critical = false
+ end
+
def set_last_thread(th)
@last_thread = th
end
+ def suspend_all_thread
+ Thread.critical = true
+ make_thread_list
+ for th in @thread_list
+ next if th[0] == Thread.current
+ context(th[0]).suspend
+ end
+ Thread.critical = false
+ # Schedule other threads to suspend as soon as possible.
+ Thread.pass
+ end
+
+ def resume_all_thread
+ Thread.critical = true
+ waiting.each do |th|
+ th.run
+ end
+ waiting.clear
+ Thread.critical = false
+ # Schedule other threads to restart as soon as possible.
+ Thread.pass
+ end
+
def context(thread=Thread.current)
c = thread[:__debugger_data__]
@@ -727,5 +806,5 @@ EOHELP
th = @thread_list.index(num)
unless th
- @stdout.print "no thread no.", num, "\n"
+ @stdout.print "No thread ##{num}\n"
throw :debug_error
end
@@ -774,22 +853,43 @@ EOHELP
thread_list_all
- when /^c(?:ur(?:rent)?)?\s+(\d+)/, /^stop\s+(\d+)/, /^(\d+)/
+ when /^c(?:ur(?:rent)?)?$/
+ make_thread_list
+ thread_list(@thread_list[Thread.current])
+
+ when /^(?:sw(?:itch)?\s+)?(\d+)/
make_thread_list
th = get_thread($1.to_i)
- thread_list(@thread_list[th])
- context(th).stop_next
- th.run
- return :cont
+ if th == Thread.current
+ @stdout.print "It's the current thread.\n"
+ else
+ thread_list(@thread_list[th])
+ context(th).stop_next
+ th.run
+ return :cont
+ end
- when /^c(?:ur(?:rent)?)?$/
+ when /^stop\s+(\d+)/
make_thread_list
- thread_list(@thread_list[Thread.current])
+ th = get_thread($1.to_i)
+ if th == Thread.current
+ @stdout.print "It's the current thread.\n"
+ elsif th.stop?
+ @stdout.print "Already stopped.\n"
+ else
+ thread_list(@thread_list[th])
+ context(th).suspend
+ end
when /^resume\s+(\d+)/
make_thread_list
th = get_thread($1.to_i)
- thread_list(@thread_list[th])
- th.run
- return :cont
+ if th == Thread.current
+ @stdout.print "It's the current thread.\n"
+ elsif !th.stop?
+ @stdout.print "Already running."
+ else
+ thread_list(@thread_list[th])
+ th.run
+ end
end
end
@@ -798,6 +898,6 @@ EOHELP
stdout.printf "Debug.rb\n"
stdout.printf "Emacs support available.\n\n"
- set_trace_func proc{|event, file, line, id, binding,klass,*rest|
- DEBUGGER__.context.trace_func event, file, line, id, binding,klass
+ set_trace_func proc { |event, file, line, id, binding, klass, *rest|
+ DEBUGGER__.context.trace_func event, file, line, id, binding, klass
}
end