I'm looking for a portable interface to POSIX alarm(2)
(or similar) in Ruby. That's to say, I would like to be able to set a background timer to send a signal to the current process after n seconds.
I have found some good discussion from 2006 on the ruby-talk list that provides a solution using dl/import
, but that's a bit of a hack (albeit a neat hack) and not very portable.
I've looked at the much-maligned Timeout
module and that won't cut it under JRuby although it works fine with the traditional interpreter. My program is a small command-line shell that uses the Readline library:
TIMEOUT = 5 # seconds
loop do
input = nil
begin
Timeout.timeout(TIMEOUT) do
input = Readline::readline('> ', nil)
end
rescue Timeout::Error
puts "Timeout"
next
end
# do something with input
end
Under JRuby it seems the process blocks in the readline
call and Timeout::Error
is only thrown after (a) the timer expires and (b) the user enters a new line. And the exception doesn't get rescued. Hmm.
So I came up with this workaround:
require 'readline'
class TimeoutException < Exception ; end
TIMEOUT = 5 # seconds
loop do
input = nil
start_time = Time.now
thread = Thread.new { input = Readline::readline('> ', nil) }
begin
while thread.alive? do
sleep(1) # prevent CPU from melting
raise TimeoutException if(Time.now - start_time > TIMEOUT)
end
rescue TimeoutException
thread.exit
puts "Timeout"
end
# do something with input
end
This is... clunky (let's be polite). I just want alarm(2)
! I don't really want to drag in non-core libraries (eg Terminator) for this. Is there a better way?
EDIT: I can't get another alternative -- creating a thread that sleeps and then sends a signal to the process -- to work under JRuby either. Does JRuby eat signals? Example:
SIG = 'USR2'
Signal.trap(SIG) { raise }
Process.kill(SIG, Process.pid)
JRuby simply returns, Ruby returns the expected "unhandled exception" error.