@@ -79,6 +79,70 @@ def timeout(sec, klass = nil, message = nil, &blk)
79
79
end
80
80
module_function :timeout
81
81
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
+
82
146
def terminate ( pid , signal = :TERM , pgroup = nil , reprieve = 1 )
83
147
reprieve = apply_timeout_scale ( reprieve ) if reprieve
84
148
@@ -94,17 +158,10 @@ def terminate(pid, signal = :TERM, pgroup = nil, reprieve = 1)
94
158
pgroup = pid
95
159
end
96
160
97
- lldb = true if /darwin/ =~ RUBY_PLATFORM
98
-
99
161
while signal = signals . shift
100
162
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 )
108
165
end
109
166
110
167
begin
0 commit comments