module Timeout

def self.create_timeout_thread

def self.create_timeout_thread
  watcher = Thread.new do
    requests = []
    while true
      until QUEUE.empty? and !requests.empty? # wait to have at least one request
        req = QUEUE.pop
        requests << req unless req.done?
      end
      closest_deadline = requests.min_by(&:deadline).deadline
      now = 0.0
      QUEUE_MUTEX.synchronize do
        while (now = GET_TIME.call(Process::CLOCK_MONOTONIC)) < closest_deadline and QUEUE.empty?
          CONDVAR.wait(QUEUE_MUTEX, closest_deadline - now)
        end
      end
      requests.each do |req|
        req.interrupt if req.expired?(now)
      end
      requests.reject!(&:done?)
    end
  end
  ThreadGroup::Default.add(watcher) unless watcher.group.enclosed?
  watcher.name = "Timeout stdlib thread"
  watcher.thread_variable_set(:"\0__detached_thread__", true)
  watcher
end

def self.ensure_timeout_thread_created

def self.ensure_timeout_thread_created
  unless @timeout_thread and @timeout_thread.alive?
    TIMEOUT_THREAD_MUTEX.synchronize do
      unless @timeout_thread and @timeout_thread.alive?
        @timeout_thread = create_timeout_thread
      end
    end
  end
end

def timeout(sec, klass = nil, message = nil, &block) #:yield: +sec+

:yield: +sec+
a module method, so you can call it directly as Timeout.timeout().
Timeout into your classes so they have a #timeout method, as well as
Note that this is both a method of module Timeout, so you can include

Scheduler#timeout_after.
If a scheduler is defined, it will be used to handle the timeout by invoking

method cannot be relied on to enforce timeouts for untrusted blocks.
ensure to prevent the handling of the exception. For that reason, this
the block unless +klass+ is given explicitly. However, the block can use
The exception thrown to terminate the given block cannot be rescued inside

+sec+ seconds, otherwise throws an exception, based on the value of +klass+.
Returns the result of the block *if* the block completed before

Omitting will use the default, "execution expired"
+message+:: Error message to raise with Exception Class.
in +sec+ seconds. Omitting will use the default, Timeout::Error
+klass+:: Exception Class to raise if the block fails to terminate
Any negative number will raise an ArgumentError.
value of 0 or +nil+ will execute the block without any timeout.
or nil may be used, including Floats to specify fractional seconds. A
+sec+:: Number of seconds to wait for the block to terminate. Any non-negative number

+sec+ seconds to complete.
Perform an operation in a block, raising an error if it takes longer than
def timeout(sec, klass = nil, message = nil, &block)   #:yield: +sec+
  return yield(sec) if sec == nil or sec.zero?
  raise ArgumentError, "Timeout sec must be a non-negative number" if 0 > sec
  message ||= "execution expired"
  if Fiber.respond_to?(:current_scheduler) && (scheduler = Fiber.current_scheduler)&.respond_to?(:timeout_after)
    return scheduler.timeout_after(sec, klass || Error, message, &block)
  end
  Timeout.ensure_timeout_thread_created
  perform = Proc.new do |exc|
    request = Request.new(Thread.current, sec, exc, message)
    QUEUE_MUTEX.synchronize do
      QUEUE << request
      CONDVAR.signal
    end
    begin
      return yield(sec)
    ensure
      request.finished
    end
  end
  if klass
    perform.call(klass)
  else
    Error.handle_timeout(message, &perform)
  end
end