123456789_123456789_123456789_123456789_123456789_

Class: Timeout::State

Do not use. This class is for internal use only.
Relationships & Source Files
Inherits: Object
Defined in: lib/timeout.rb

Constant Summary

Class Method Summary

Instance Method Summary

Constructor Details

.newState

[ GitHub ]

  
# File 'lib/timeout.rb', line 57

def initialize
  @condvar = ConditionVariable.new
  @queue = Queue.new
  @queue_mutex = Mutex.new

  @timeout_thread = nil
  @timeout_thread_mutex = Mutex.new
end

Class Method Details

.instance

Ractor support if

  1. Ractor.store_if_absent is available

  2. Method object can be shareable (4.0~)

See additional method definition at line 70.

[ GitHub ]

  
# File 'lib/timeout.rb', line 78

def self.instance
  Ractor.store_if_absent :timeout_gem_state do
    State.new
  end
end

Instance Method Details

#add_request(request)

[ GitHub ]

  
# File 'lib/timeout.rb', line 134

def add_request(request)
  Sync.synchronize @queue_mutex do
    @queue << request
    @condvar.signal
  end
end

#create_timeout_thread

[ GitHub ]

  
# File 'lib/timeout.rb', line 83

def create_timeout_thread
  # Threads unexpectedly inherit the interrupt mask: https://github.com/ruby/timeout/issues/41
  # So reset the interrupt mask to the default one for the timeout thread
  Thread.handle_interrupt(Object => :immediate) do
    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

    if !watcher.group.enclosed? && (!defined?(Ractor.main?) || Ractor.main?)
      ThreadGroup::Default.add(watcher)
    end

    watcher.name = "Timeout stdlib thread"
    watcher.thread_variable_set(:"\0__detached_thread__", true)
    watcher
  end
end

#ensure_timeout_thread_created

[ GitHub ]

  
# File 'lib/timeout.rb', line 120

def ensure_timeout_thread_created
  unless @timeout_thread&.alive?
    # If the Mutex is already owned we are in a signal handler.
    # In that case, just return and let the main thread create the Timeout thread.
    return if @timeout_thread_mutex.owned?

    Sync.synchronize @timeout_thread_mutex do
      unless @timeout_thread&.alive?
        @timeout_thread = create_timeout_thread
      end
    end
  end
end