Daemonize

Public Class Methods

call_as_daemon(block, logfile_name = nil, app_name = nil) click to toggle source

Call a given block as a daemon

# File lib/daemons/daemonize.rb, line 39
def call_as_daemon(block, logfile_name = nil, app_name = nil)
  # we use a pipe to return the PID of the daemon
  rd, wr = IO.pipe
  
  if tmppid = safefork
    # in the parent
    
    wr.close
    pid = rd.read.to_i
    rd.close
    
    Process.waitpid(tmppid)
    
    return pid
  else
    # in the child
    
    rd.close
    
    # Detach from the controlling terminal
    unless sess_id = Process.setsid
      raise Daemons.RuntimeException.new('cannot detach from controlling terminal')
    end

    # Prevent the possibility of acquiring a controlling terminal
    trap 'SIGHUP', 'IGNORE'
    exit if pid = safefork

    wr.write Process.pid
    wr.close
    
    $0 = app_name if app_name
    
    # Release old working directory
    Dir.chdir "/"   

    close_io()

    redirect_io(logfile_name)  
  
    # Split rand streams between spawning and daemonized process
    srand
    
    block.call
    
    exit
  end
end
close_io() click to toggle source
# File lib/daemons/daemonize.rb, line 121
def close_io()
  # Make sure all input/output streams are closed
  # Part I: close all IO objects (except for STDIN/STDOUT/STDERR)
  ObjectSpace.each_object(IO) do |io|
    unless [STDIN, STDOUT, STDERR].include?(io)
      begin
        unless io.closed?
          io.close
        end
      rescue ::Exception
      end
    end
  end
  
  # Make sure all input/output streams are closed
  # Part II: close all file decriptors (except for STDIN/STDOUT/STDERR)
  ios = Array.new(8192) {|i| IO.for_fd(i) rescue nil}.compact
  ios.each do |io|
    next if io.fileno < 3
    io.close
  end
end
daemonize(logfile_name = nil, app_name = nil) click to toggle source

Transform the current process into a daemon

# File lib/daemons/daemonize.rb, line 91
def daemonize(logfile_name = nil, app_name = nil)
  # Fork and exit from the parent
  safefork and exit

  # Detach from the controlling terminal
  unless sess_id = Process.setsid
    raise Daemons.RuntimeException.new('cannot detach from controlling terminal')
  end

  # Prevent the possibility of acquiring a controlling terminal
  trap 'SIGHUP', 'IGNORE'
  exit if pid = safefork
  
  $0 = app_name if app_name
  
  # Release old working directory
  Dir.chdir "/"  

  close_io()

  redirect_io(logfile_name)
  
  # Split rand streams between spawning and daemonized process
  srand
  
  return sess_id
end
redirect_io(logfile_name) click to toggle source

Free STDIN/STDOUT/STDERR file descriptors and point them somewhere sensible

# File lib/daemons/daemonize.rb, line 148
def redirect_io(logfile_name)
  begin; STDIN.reopen "/dev/null"; rescue ::Exception; end       
   
  if logfile_name
    begin
      STDOUT.reopen logfile_name, "a" 
      File.chmod(0644, logfile_name)
      STDOUT.sync = true
    rescue ::Exception
      begin; STDOUT.reopen "/dev/null"; rescue ::Exception; end
    end
  else
    begin; STDOUT.reopen "/dev/null"; rescue ::Exception; end
  end
  
  begin; STDERR.reopen STDOUT; rescue ::Exception; end
  STDERR.sync = true
end
safefork() click to toggle source

Try to fork if at all possible retrying every 5 sec if the maximum process limit for the system has been reached

# File lib/daemons/daemonize.rb, line 5
def safefork
  tryagain = true

  while tryagain
    tryagain = false
    begin
      if pid = fork
        return pid
      end
    rescue Errno::EWOULDBLOCK
      sleep 5
      tryagain = true
    end
  end
end
simulate(logfile_name = nil) click to toggle source

Simulate the daemonization process (:ontop mode) NOTE: STDOUT and STDERR will not be redirected to the logfile, because in :ontop mode, we normally want to see the output

# File lib/daemons/daemonize.rb, line 26
def simulate(logfile_name = nil)
  # Release old working directory
  Dir.chdir "/"   

  close_io()

  # Free STDIN and point them somewhere sensible
  begin; STDIN.reopen "/dev/null"; rescue ::Exception; end       
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.