Skip to content

Commit df03149

Browse files
committed
jruby exec_with_allocation_control heuristic
1 parent 4b2c816 commit df03149

File tree

1 file changed

+38
-9
lines changed

1 file changed

+38
-9
lines changed

lib/ruby-debug-ide/xml_printer.rb

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)