@@ -79,6 +79,70 @@ def timeout(sec, klass = nil, message = nil, &blk)
7979 end
8080 module_function :timeout
8181
82+ class Debugger
83+ @list = [ ]
84+
85+ attr_accessor :name
86+
87+ def self . register ( name , &block )
88+ @list << new ( name , &block )
89+ end
90+
91+ def initialize ( name , &block )
92+ @name = name
93+ instance_eval ( &block )
94+ end
95+
96+ def usable? ; false ; end
97+
98+ def start ( pid , *args ) end
99+
100+ def dump ( pid , timeout : 60 , reprieve : timeout &.div ( 4 ) )
101+ dpid = start ( pid , *command_file ( File . join ( __dir__ , "dump.#{ name } " ) ) )
102+ rescue Errno ::ENOENT
103+ return
104+ else
105+ return unless dpid
106+ [ [ timeout , :TERM ] , [ reprieve , :KILL ] ] . find do |t , sig |
107+ return EnvUtil . timeout ( t ) { Process . wait ( dpid ) }
108+ rescue Timeout ::Error
109+ Process . kill ( sig , dpid )
110+ end
111+ true
112+ end
113+
114+ # sudo -n: --non-interactive
115+ PRECOMMAND = ( %[sudo -n] if /darwin/ =~ RUBY_PLATFORM )
116+
117+ def spawn ( *args , **opts )
118+ super ( *PRECOMMAND , *args , **opts )
119+ end
120+
121+ register ( "gdb" ) do
122+ class << self
123+ def usable? ; system ( *%w[ gdb --batch --quiet --nx -ex exit ] ) ; end
124+ def start ( pid , *args )
125+ spawn ( *%w[ gdb --batch --quiet --pid #{pid} ] , *args )
126+ end
127+ def command_file ( file ) "--command=#{ file } " ; end
128+ end
129+ end
130+
131+ register ( "lldb" ) do
132+ class << self
133+ def usable? ; system ( *%w[ lldb -Q --no-lldbinit -o exit ] ) ; end
134+ def start ( pid , *args )
135+ spawn ( *%w[ lldb --batch -Q --attach-pid #{pid} ] )
136+ end
137+ def command_file ( file ) [ "--source" , file ] ; end
138+ end
139+ end
140+
141+ def self . search
142+ @debugger ||= @list . find ( &:usable? )
143+ end
144+ end
145+
82146 def terminate ( pid , signal = :TERM , pgroup = nil , reprieve = 1 )
83147 reprieve = apply_timeout_scale ( reprieve ) if reprieve
84148
@@ -94,17 +158,10 @@ def terminate(pid, signal = :TERM, pgroup = nil, reprieve = 1)
94158 pgroup = pid
95159 end
96160
97- lldb = true if /darwin/ =~ RUBY_PLATFORM
98-
99161 while signal = signals . shift
100162
101- if lldb and [ :ABRT , :KILL ] . include? ( signal )
102- lldb = false
103- # sudo -n: --non-interactive
104- # lldb -p: attach
105- # -o: run command
106- system ( *%W[ sudo -n lldb -p #{ pid } --batch -o bt\ all -o call\ rb_vmdebug_stack_dump_all_threads() -o quit ] )
107- true
163+ if ( dbg = Debugger . search ) and [ :ABRT , :KILL ] . include? ( signal )
164+ dbg . dump ( pid )
108165 end
109166
110167 begin
0 commit comments