class MU::Thread

Subclass core thread so we can gracefully handle it when we hit system thread limits. Back off and wait makes sense for us, since most of our threads are terminal (in the dependency sense) and this is unlikely to get us deadlocks.

Public Class Methods

new(*args, &block) click to toggle source
Calls superclass method
# File modules/mu.rb, line 237
def initialize(*args, &block)
  @@mu_global_thread_semaphore.synchronize {
    @@mu_global_threads.reject! { |t| t.nil? or !t.status }
  }
  newguy = nil
  start = Time.now
  begin
    newguy = super(*args, &block)
    if newguy.nil?
      MU.log "I somehow got a nil trying to create a thread", MU::WARN, details: caller
      sleep 1
    end
  rescue ::ThreadError => e
    if e.message.match(/Resource temporarily unavailable/)
      toomany = @@mu_global_threads.size
      MU.log "Hit the wall at #{toomany.to_s} threads, waiting until there are fewer", MU::WARN
      if @@mu_global_threads.size >= toomany
        sleep 1
        begin
          @@mu_global_thread_semaphore.synchronize {
            @@mu_global_threads.each { |t|
              next if t == ::Thread.current
              t.join(0.1)
            }
            @@mu_global_threads.reject! { |t| t.nil? or !t.status }
          }
          if (Time.now - start) > 150
            MU.log "Failed to get a free thread slot after 150 seconds- are we in a deadlock situation?", MU::ERR, details: caller
            raise e
          end
        end while @@mu_global_threads.size >= toomany
      end
      retry
    else
      raise e
    end
  end while newguy.nil?

  @@mu_global_thread_semaphore.synchronize {
    MU.dupGlobals(Thread.current.object_id, target_thread: newguy)
    @@mu_global_threads << newguy
  }

end