module PhusionPassenger::PreloaderSharedHelpers

def accept_and_process_next_client(server_socket)

def accept_and_process_next_client(server_socket)
	original_pid = Process.pid
	client = server_socket.accept
	client.binmode
	begin
		command = client.readline
	rescue EOFError
		return nil
	end
	if command !~ /\n\Z/
		STDERR.puts "Command must end with a newline"
	elsif command == "spawn\n"
		while client.readline != "\n"
			# Do nothing.
		end
		
		# Improve copy-on-write friendliness.
		GC.start
		
		pid = fork
		if pid.nil?
			$0 = "#{$0} (forking...)"
			client.puts "OK"
			client.puts Process.pid
			client.flush
			client.sync = true
			return [:forked, client]
		elsif defined?(NativeSupport)
			NativeSupport.detach_process(pid)
		else
			Process.detach(pid)
		end
	else
		STDERR.puts "Unknown command '#{command.inspect}'"
	end
	return nil
ensure
	if client && Process.pid == original_pid
		begin
			client.close
		rescue Errno::EINVAL
			# Work around OS X bug.
			# https://code.google.com/p/phusion-passenger/issues/detail?id=854
		end
	end
end

def init(options)

def init(options)
	if !Kernel.respond_to?(:fork)
		message = "Smart spawning is not available on this Ruby " +
			"implementation because it does not support `Kernel.fork`. "
		if ENV['SERVER_SOFTWARE'].to_s =~ /nginx/i
			message << "Please set `passenger_spawn_method` to `direct`."
		else
			message << "Please set `PassengerSpawnMethod` to `direct`."
		end
		raise(message)
	end
	return options
end

def run_main_loop(options)

def run_main_loop(options)
	$0 = "Passenger AppPreloader: #{options['app_root']}"
	client = nil
	original_pid = Process.pid
	socket_filename = "#{options['generation_dir']}/backends/preloader.#{Process.pid}"
	server = UNIXServer.new(socket_filename)
	server.close_on_exec!
	
	# Update the dump information just before telling the preloader that we're
	# ready because the HelperAgent will read and memorize this information.
	LoaderSharedHelpers.dump_all_information
	puts "!> Ready"
	puts "!> socket: unix:#{socket_filename}"
	puts "!> "
	
	while true
		# We call ::select just in case someone overwrites the global select()
		# function by including ActionView::Helpers in the wrong place.
		# https://code.google.com/p/phusion-passenger/issues/detail?id=915
		ios = Kernel.select([server, STDIN])[0]
		if ios.include?(server)
			result, client = accept_and_process_next_client(server)
			if result == :forked
				STDIN.reopen(client)
				STDOUT.reopen(client)
				STDOUT.sync = true
				client.close
				return :forked
			end
		end
		if ios.include?(STDIN)
			if STDIN.tty?
				begin
					# Prevent bash from exiting when we press Ctrl-D.
					STDIN.read_nonblock(1)
				rescue Errno::EAGAIN
					# Do nothing.
				end
			end
			break
		end
	end
	return nil
ensure
	server.close if server
	if original_pid == Process.pid
		File.unlink(socket_filename) rescue nil
	end
end