The XCPU signal (SIGXCPU
) is only sent upon a soft limit. When the hard limit is reached, a KILL signal (SIGKILL
) is sent instead. KILL signals cause the program to terminate immediately, and cannot be caught.
Taken from here:
The XCPU signal is sent to a process when it has used up the CPU for a
duration that exceeds a certain predetermined user-settable value. The
arrival of an XCPU signal provides the receiving process a chance to
quickly save any intermediate results and to exit gracefully, before
it is terminated by the operating system using the SIGKILL signal.
The KILL signal is sent to a process to cause it to terminate
immediately. In contrast to SIGTERM and SIGINT, this signal cannot be
caught or ignored, and the receiving process cannot perform any
clean-up upon receiving this signal.
By calling Process.setrlimit
without a second parameter, the hard limit defaults to being equal to the soft limit. As such, at least on your operating system, it seems the SIGKILL
is being sent before a SIGXCPU
can be handled by your trap
block.
Here is a quick demo to show why the second approach always works:
t = Time.now
trap("XCPU") do
abort "Max Time exceeded. Total running time: #{(Time.now - t).round} seconds"
end
Process.setrlimit(:CPU, 2, 5)
loop do
end
# => "Max Time exceeded. Total running time: 2 seconds"
The hard limit is not reached before the trap
block executes, so the code runs as you expect.