@@ -25,9 +25,19 @@ def initialize(message, trace_point, backtrace = [])
2525 end
2626 end
2727
28- class MemoryLimitError < ExecError ; end
28+ class JrubyTimeLimitError < StandardError
29+ attr_reader :message
2930
30- class TimeLimitError < ExecError ; end
31+ def initialize ( message )
32+ @message = message
33+ end
34+ end
35+
36+ class MemoryLimitError < ExecError ;
37+ end
38+
39+ class TimeLimitError < ExecError ;
40+ end
3141
3242 class XmlPrinter # :nodoc:
3343 class ExceptionProxy
@@ -163,10 +173,28 @@ def print_string(string)
163173 end
164174 end
165175
176+ def jruby_timeout ( sec )
177+ return yield if sec == nil or sec . zero?
178+ if Thread . respond_to? ( :critical ) and Thread . critical
179+ raise ThreadError , "timeout within critical session"
180+ end
181+ begin
182+ x = Thread . current
183+ y = DebugThread . start {
184+ sleep sec
185+ x . raise JrubyTimeLimitError . new ( "Timeout: evaluation took longer than #{ sec } seconds." ) if x . alive?
186+ }
187+ yield sec
188+ ensure
189+ y . kill if y and y . alive?
190+ end
191+ end
192+
166193 def exec_with_allocation_control ( value , memory_limit , time_limit , exec_method , overflow_message_type )
167194 return value . send exec_method if RUBY_VERSION < '2.0'
168195
169- check_memory_limit = !defined? ( JRUBY_VERSION ) && ENV [ 'DEBUGGER_MEMORY_LIMIT' ] . to_i > 0
196+ return jruby_timeout ( time_limit /1e3 ) { value . send exec_method } if defined? ( JRUBY_VERSION )
197+
170198 curr_thread = Thread . current
171199
172200 result = nil
@@ -184,13 +212,11 @@ def exec_with_allocation_control(value, memory_limit, time_limit, exec_method, o
184212 curr_thread . raise TimeLimitError . new ( "Timeout: evaluation of #{ exec_method } took longer than #{ time_limit } ms." , trace_point , caller . to_a )
185213 end
186214
187- if check_memory_limit
188- curr_alloc_size = ObjectSpace . memsize_of_all
189- start_alloc_size = curr_alloc_size if curr_alloc_size < start_alloc_size
215+ curr_alloc_size = ObjectSpace . memsize_of_all
216+ start_alloc_size = curr_alloc_size if curr_alloc_size < start_alloc_size
190217
191- if curr_alloc_size - start_alloc_size > 1e6 * memory_limit
192- curr_thread . raise MemoryLimitError . new ( "Out of memory: evaluation of #{ exec_method } took more than #{ memory_limit } mb." , trace_point , caller . to_a )
193- end
218+ if curr_alloc_size - start_alloc_size > 1e6 * memory_limit
219+ curr_thread . raise MemoryLimitError . new ( "Out of memory: evaluation of #{ exec_method } took more than #{ memory_limit } mb." , trace_point , caller . to_a )
194220 end
195221 end
196222 trace_point . enable
@@ -203,6 +229,9 @@ def exec_with_allocation_control(value, memory_limit, time_limit, exec_method, o
203229 e . trace_point . disable
204230 print_debug ( e . message + "\n " + e . backtrace . map { |l | "\t #{ l } " } . join ( "\n " ) )
205231 return overflow_message_type . call ( e )
232+ rescue JrubyTimeLimitError => e
233+ print_debug ( e . message )
234+ return overflow_message_type . call ( e )
206235 ensure
207236 inspect_thread . kill if inspect_thread && inspect_thread . alive?
208237 end
0 commit comments