# File lib/merb-core/rack/adapter/abstract.rb, line 73 def self.start(opts={}) @opts = opts $WORKERS ||= [] parent = nil @pids = {} port = (opts[:socket] || opts[:port]).to_i max_port = Merb::Config[:cluster] ? Merb::Config[:cluster] - 1 : 0 # If we only have a single merb, just start it up and dispense with # the spawner/worker setup. if max_port == 0 start_at_port(port) return end $0 = process_title(:spawner, port) # For each port, spawn a new worker. The parent will continue in # the loop, while the worker will throw :new_worker and be booted # out of the loop. catch(:new_worker) do 0.upto(max_port) do |i| parent = spawn_worker(port + i) end end # If we're in a worker, we're done. Otherwise, we've completed # setting up workers and now need to watch them. return unless parent # For each worker, set up a thread in the spawner to watch it 0.upto(max_port) do |i| Thread.new do catch(:new_worker) do loop do pid = @pids[port + i] begin # Watch for the pid to exit. _, status = Process.wait2(pid) # If the pid doesn't exist, we want to silently exit instead of # raising here. rescue SystemCallError => e ensure # If there was no worker with that PID, the status was non-0 # (we send back a status of 128 when ABRT is called on a # worker, and Merb.fatal! exits with a status of 1), or if # Merb is in the process of exiting, *then* don't respawn. # Note that processes killed with kill -9 will return no # exitstatus, and we respawn them. if !status || (status.exitstatus && status.exitstatus != 0) || Merb.exiting then Thread.exit end end # Otherwise, respawn the worker, and watch it again. spawn_worker(port + i) end end end end # The spawner process will make it here, and when it does, it should just # sleep so it can pick up ctrl-c if it's in console mode. sleep end