@@ -15,17 +15,15 @@ module OverflowMessageType
15
15
16
16
class ExecError < StandardError
17
17
attr_reader :message
18
- attr_reader :trace_point
19
18
attr_reader :backtrace
20
19
21
- def initialize ( message , trace_point , backtrace = [ ] )
20
+ def initialize ( message , backtrace = [ ] )
22
21
@message = message
23
- @trace_point = trace_point
24
22
@backtrace = backtrace
25
23
end
26
24
end
27
25
28
- class JrubyTimeLimitError < StandardError
26
+ class SimpleTimeLimitError < StandardError
29
27
attr_reader :message
30
28
31
29
def initialize ( message )
@@ -173,7 +171,7 @@ def print_string(string)
173
171
end
174
172
end
175
173
176
- def jruby_timeout ( sec )
174
+ def exec_with_timeout ( sec )
177
175
return yield if sec == nil or sec . zero?
178
176
if Thread . respond_to? ( :critical ) and Thread . critical
179
177
raise ThreadError , "timeout within critical session"
@@ -182,7 +180,7 @@ def jruby_timeout(sec)
182
180
x = Thread . current
183
181
y = DebugThread . start {
184
182
sleep sec
185
- x . raise JrubyTimeLimitError . new ( "Timeout: evaluation took longer than #{ sec } seconds." ) if x . alive?
183
+ x . raise SimpleTimeLimitError . new ( "Timeout: evaluation took longer than #{ sec } seconds." ) if x . alive?
186
184
}
187
185
yield sec
188
186
ensure
@@ -191,48 +189,57 @@ def jruby_timeout(sec)
191
189
end
192
190
193
191
def exec_with_allocation_control ( value , memory_limit , time_limit , exec_method , overflow_message_type )
194
- return jruby_timeout ( time_limit / 1e3 ) { value . send exec_method } if defined? ( JRUBY_VERSION )
192
+ return exec_with_timeout ( time_limit * 1e-3 ) { value . send exec_method } if defined? ( JRUBY_VERSION ) || memory_limit <= 0 || ( RUBY_VERSION < '2.0' && time_limit > 0 )
195
193
return value . send exec_method if RUBY_VERSION < '2.0'
196
194
197
195
curr_thread = Thread . current
196
+ control_thread = Debugger . control_thread
198
197
199
198
result = nil
199
+
200
+ trace_queue = Queue . new
201
+
200
202
inspect_thread = DebugThread . start do
201
- start_alloc_size = ObjectSpace . memsize_of_all if check_memory_limit
203
+ start_alloc_size = ObjectSpace . memsize_of_all
202
204
start_time = Time . now . to_f
203
205
204
- trace_point = TracePoint . new ( :c_call , :call ) do | |
205
- next unless Thread . current == inspect_thread
206
- next unless rand > 0.75
207
-
206
+ trace_point = TracePoint . new ( :c_call , :call ) do |tp |
208
207
curr_time = Time . now . to_f
209
208
210
209
if ( curr_time - start_time ) * 1e3 > time_limit
211
- curr_thread . raise TimeLimitError . new ( "Timeout: evaluation of #{ exec_method } took longer than #{ time_limit } ms." , trace_point , caller . to_a )
210
+ trace_queue << TimeLimitError . new ( "Timeout: evaluation of #{ exec_method } took longer than #{ time_limit } ms." , caller . to_a )
211
+ trace_point . disable
212
+ inspect_thread . kill
212
213
end
213
214
215
+ next unless rand > 0.75
216
+
214
217
curr_alloc_size = ObjectSpace . memsize_of_all
215
218
start_alloc_size = curr_alloc_size if curr_alloc_size < start_alloc_size
216
219
217
220
if curr_alloc_size - start_alloc_size > 1e6 * memory_limit
218
- curr_thread . raise MemoryLimitError . new ( "Out of memory: evaluation of #{ exec_method } took more than #{ memory_limit } mb." , trace_point , caller . to_a )
221
+ trace_queue << MemoryLimitError . new ( "Out of memory: evaluation of #{ exec_method } took more than #{ memory_limit } mb." , caller . to_a )
222
+ trace_point . disable
223
+ inspect_thread . kill
219
224
end
220
225
end
221
226
trace_point . enable
222
227
result = value . send exec_method
228
+ trace_queue << result
223
229
trace_point . disable
224
230
end
225
- inspect_thread . join
226
- return result
227
- rescue ExecError => e
228
- e . trace_point . disable
229
- print_debug ( e . message + "\n " + e . backtrace . map { |l | "\t #{ l } " } . join ( "\n " ) )
230
- return overflow_message_type . call ( e )
231
- rescue JrubyTimeLimitError => e
231
+
232
+ while ( mes = trace_queue . pop )
233
+ if ( mes . is_a? TimeLimitError or mes . is_a? MemoryLimitError )
234
+ print_debug ( mes . message + "\n " + mes . backtrace . map { |l | "\t #{ l } " } . join ( "\n " ) )
235
+ return overflow_message_type . call ( mes )
236
+ else
237
+ return mes
238
+ end
239
+ end
240
+ rescue SimpleTimeLimitError => e
232
241
print_debug ( e . message )
233
242
return overflow_message_type . call ( e )
234
- ensure
235
- inspect_thread . kill if inspect_thread && inspect_thread . alive?
236
243
end
237
244
238
245
def print_variable ( name , value , kind )
0 commit comments