@@ -15,17 +15,15 @@ module OverflowMessageType
1515
1616 class ExecError < StandardError
1717 attr_reader :message
18- attr_reader :trace_point
1918 attr_reader :backtrace
2019
21- def initialize ( message , trace_point , backtrace = [ ] )
20+ def initialize ( message , backtrace = [ ] )
2221 @message = message
23- @trace_point = trace_point
2422 @backtrace = backtrace
2523 end
2624 end
2725
28- class JrubyTimeLimitError < StandardError
26+ class SimpleTimeLimitError < StandardError
2927 attr_reader :message
3028
3129 def initialize ( message )
@@ -173,7 +171,7 @@ def print_string(string)
173171 end
174172 end
175173
176- def jruby_timeout ( sec )
174+ def exec_with_timeout ( sec )
177175 return yield if sec == nil or sec . zero?
178176 if Thread . respond_to? ( :critical ) and Thread . critical
179177 raise ThreadError , "timeout within critical session"
@@ -182,7 +180,7 @@ def jruby_timeout(sec)
182180 x = Thread . current
183181 y = DebugThread . start {
184182 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?
186184 }
187185 yield sec
188186 ensure
@@ -191,48 +189,57 @@ def jruby_timeout(sec)
191189 end
192190
193191 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 )
195193 return value . send exec_method if RUBY_VERSION < '2.0'
196194
197195 curr_thread = Thread . current
196+ control_thread = Debugger . control_thread
198197
199198 result = nil
199+
200+ trace_queue = Queue . new
201+
200202 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
202204 start_time = Time . now . to_f
203205
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 |
208207 curr_time = Time . now . to_f
209208
210209 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
212213 end
213214
215+ next unless rand > 0.75
216+
214217 curr_alloc_size = ObjectSpace . memsize_of_all
215218 start_alloc_size = curr_alloc_size if curr_alloc_size < start_alloc_size
216219
217220 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
219224 end
220225 end
221226 trace_point . enable
222227 result = value . send exec_method
228+ trace_queue << result
223229 trace_point . disable
224230 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
232241 print_debug ( e . message )
233242 return overflow_message_type . call ( e )
234- ensure
235- inspect_thread . kill if inspect_thread && inspect_thread . alive?
236243 end
237244
238245 def print_variable ( name , value , kind )
0 commit comments