module TimeoutInterruptSingleton

Helper module for `TimeoutInterrupt` @see TimeoutInterrupt

Public Class Methods

alarm_trap(sig) click to toggle source

If there's a timed out timeout, it will raise its exception. Can be used for handling ALRM-signal. It will prepare the next timeout, too.

The timeout will not removed from timeouts, because it is timed out, yet. First, if timeout-scope will be exit, it will be removed.

@return [nil]

# File lib/timeout_interrupt.rb, line 43
def alarm_trap sig
        raise_if_sb_timed_out
        setup
end
raise_if_sb_timed_out() click to toggle source

There is a timed out timeout? It will raise it! You need not to check it yourself, it will do it for you.

@return [nil]

# File lib/timeout_interrupt.rb, line 52
def raise_if_sb_timed_out
        return  if self.timeouts.empty?
        key, (at, bt, exception) = self.timeouts.min_by {|key,(at,bt,ex)| at }
        return  if Time.now < at
        raise exception, 'execution expired', bt
end
setup() click to toggle source

Prepares the next timeout. Sets the trap and the shortest timeout as alarm.

@return [nil]

# File lib/timeout_interrupt.rb, line 62
def setup
        if timeouts.empty?
                Signal.trap( 'ALRM') {}
                FFI::LibC.alarm 0
        else
                raise_if_sb_timed_out
                Signal.trap 'ALRM', &method( :alarm_trap)
                key, (at, bt) = timeouts.min_by {|key,(at,bt)| at }
                FFI::LibC.alarm (at - Time.now).to_i + 1
        end
        nil
end
timeout(seconds = nil, exception = nil) { |seconds| ... } click to toggle source

Creates a timeout and calls your block, which has to finish before timeout occurs.

@param seconds [0] No timeout, so block can take any time. @param seconds [Integer] In `seconds` Seconds, it should raise a timeout, if not finished. @param seconds [nil] If also no block given, everything will be ignored and

it will call {setup} for checking and preparing next known timeout.

@param exception [Exception] which will be raised if timed out. @param exception [nil] `TimeoutInterrupt::Error` will be used to raise. @param block [Proc] Will be called and should finish its work before it timed out. @param block [nil] Nothing will happen, instead it will return a Proc,

which can be called with a block to use the timeout.

@return If block given, the returned value of your block.

Or if not, it will return a Proc, which will expect a Proc if called.
This Proc has no arguments and will prepare a timeout, like if you had given a block.

You can rescue `Timeout::Error`, instead `TimeoutInterrupt::Error`, it will work too.

It will call your given block, which has `seconds` seconds to end. If you want to prepare a timeout, which should be used many times, without giving `seconds` and `exception`, you can omit the block, so, `TimeoutInterruptSingleton#timeout` will return a `Proc`, which want to have the block.

There is a problem with scoped timeouts. If you rescue a timeout in an other timeout, it's possible, that the other timeout will never timeout, because both are timed out at once. Than you need to call `TimeoutInterruptSingleton#timeout` without arguments. It will prepare the next timeout or it will raise it directy, if timed out.

@see TimeoutInterrupt.timeout @see TimeoutInterrupt#timeout @raise exception

# File lib/timeout_interrupt.rb, line 105
def timeout seconds = nil, exception = nil, &block
        return yield( seconds)  if seconds.nil? || 0 == seconds  if block_given?
        return setup  if seconds.nil?
        seconds = seconds.to_i
        exception ||= TimeoutInterrupt::Error
        raise exception, "Timeout must be longer than '0' seconds."  unless 0 < seconds
        unless block_given?
                return lambda {|&e|
                        raise exception, "Expect a lambda."  unless e
                        timeout seconds, exception, &e
                }
        end
        at = Time.now + seconds
        key, bt = Random.rand( 2**64-1), Kernel.caller
        begin
                self.timeouts[key] = [at, bt, exception]
                setup
                yield seconds
        ensure
                self.timeouts.delete key
                setup
        end
end
timeouts(thread = nil) click to toggle source

Stores all timeouts.

@param thread [nil] must be nil! Do not use it yet! @return [Hash< key(Integer): [at(Time), backtrace(Array<String>), exception(Exception)] >]

# File lib/timeout_interrupt.rb, line 29
def timeouts thread = nil
        @timeouts ||= Hash.new {|h,k| h[k] = {} }
        thread = Thread.current  unless thread.kind_of? Thread
        thread ? @timeouts[thread] : @timeouts
end