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
39:   def call_as_daemon(block, logfile_name = nil, app_name = nil)
40:     # we use a pipe to return the PID of the daemon
41:     rd, wr = IO.pipe
42:     
43:     if tmppid = safefork
44:       # in the parent
45:       
46:       wr.close
47:       pid = rd.read.to_i
48:       rd.close
49:       
50:       Process.waitpid(tmppid)
51:       
52:       return pid
53:     else
54:       # in the child
55:       
56:       rd.close
57:       
58:       # Detach from the controlling terminal
59:       unless sess_id = Process.setsid
60:         raise Daemons.RuntimeException.new('cannot detach from controlling terminal')
61:       end
62:   
63:       # Prevent the possibility of acquiring a controlling terminal
64:       trap 'SIGHUP', 'IGNORE'
65:       exit if pid = safefork
66:   
67:       wr.write Process.pid
68:       wr.close
69:       
70:       $0 = app_name if app_name
71:       
72:       # Release old working directory
73:       Dir.chdir "/"   
74:   
75:       close_io()
76: 
77:       redirect_io(logfile_name)  
78:     
79:       block.call
80:       
81:       exit
82:     end
83:   end
close_io() click to toggle source
     # File lib/daemons/daemonize.rb, line 118
118:   def close_io()
119:     # Make sure all input/output streams are closed
120:     # Part I: close all IO objects (except for STDIN/STDOUT/STDERR)
121:     ObjectSpace.each_object(IO) do |io|
122:       unless [STDIN, STDOUT, STDERR].include?(io)
123:         begin
124:           unless io.closed?
125:             io.close
126:           end
127:         rescue ::Exception
128:         end
129:       end
130:     end
131:     
132:     # Make sure all input/output streams are closed
133:     # Part II: close all file decriptors (except for STDIN/STDOUT/STDERR)
134:     ios = Array.new(8192) {|i| IO.for_fd(i) rescue nil}.compact
135:     ios.each do |io|
136:       next if io.fileno < 3
137:       io.close
138:     end
139:   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 88
 88:   def daemonize(logfile_name = nil, app_name = nil)
 89:     # Split rand streams between spawning and daemonized process
 90:     srand 
 91:     
 92:      # Fork and exit from the parent
 93:     safefork and exit
 94: 
 95:     # Detach from the controlling terminal
 96:     unless sess_id = Process.setsid
 97:       raise Daemons.RuntimeException.new('cannot detach from controlling terminal')
 98:     end
 99: 
100:     # Prevent the possibility of acquiring a controlling terminal
101:     trap 'SIGHUP', 'IGNORE'
102:     exit if pid = safefork
103:     
104:     $0 = app_name if app_name
105:     
106:     # Release old working directory
107:     Dir.chdir "/"  
108: 
109:     close_io()
110: 
111:     redirect_io(logfile_name)
112:     
113:     return sess_id
114:   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 145
145:   def redirect_io(logfile_name)
146:     begin; STDIN.reopen "/dev/null"; rescue ::Exception; end       
147:      
148:     if logfile_name
149:       begin
150:         STDOUT.reopen logfile_name, "a" 
151:         File.chmod(0644, logfile_name)
152:         STDOUT.sync = true
153:       rescue ::Exception
154:         begin; STDOUT.reopen "/dev/null"; rescue ::Exception; end
155:       end
156:     else
157:       begin; STDOUT.reopen "/dev/null"; rescue ::Exception; end
158:     end
159:     
160:     begin; STDERR.reopen STDOUT; rescue ::Exception; end
161:     STDERR.sync = true
162:   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
 5:   def safefork
 6:     tryagain = true
 7: 
 8:     while tryagain
 9:       tryagain = false
10:       begin
11:         if pid = fork
12:           return pid
13:         end
14:       rescue Errno::EWOULDBLOCK
15:         sleep 5
16:         tryagain = true
17:       end
18:     end
19:   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
26:   def simulate(logfile_name = nil)
27:     # Release old working directory
28:     Dir.chdir "/"   
29: 
30:     close_io()
31: 
32:     # Free STDIN and point them somewhere sensible
33:     begin; STDIN.reopen "/dev/null"; rescue ::Exception; end       
34:   end

Private Instance 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
39:   def call_as_daemon(block, logfile_name = nil, app_name = nil)
40:     # we use a pipe to return the PID of the daemon
41:     rd, wr = IO.pipe
42:     
43:     if tmppid = safefork
44:       # in the parent
45:       
46:       wr.close
47:       pid = rd.read.to_i
48:       rd.close
49:       
50:       Process.waitpid(tmppid)
51:       
52:       return pid
53:     else
54:       # in the child
55:       
56:       rd.close
57:       
58:       # Detach from the controlling terminal
59:       unless sess_id = Process.setsid
60:         raise Daemons.RuntimeException.new('cannot detach from controlling terminal')
61:       end
62:   
63:       # Prevent the possibility of acquiring a controlling terminal
64:       trap 'SIGHUP', 'IGNORE'
65:       exit if pid = safefork
66:   
67:       wr.write Process.pid
68:       wr.close
69:       
70:       $0 = app_name if app_name
71:       
72:       # Release old working directory
73:       Dir.chdir "/"   
74:   
75:       close_io()
76: 
77:       redirect_io(logfile_name)  
78:     
79:       block.call
80:       
81:       exit
82:     end
83:   end
close_io() click to toggle source
     # File lib/daemons/daemonize.rb, line 118
118:   def close_io()
119:     # Make sure all input/output streams are closed
120:     # Part I: close all IO objects (except for STDIN/STDOUT/STDERR)
121:     ObjectSpace.each_object(IO) do |io|
122:       unless [STDIN, STDOUT, STDERR].include?(io)
123:         begin
124:           unless io.closed?
125:             io.close
126:           end
127:         rescue ::Exception
128:         end
129:       end
130:     end
131:     
132:     # Make sure all input/output streams are closed
133:     # Part II: close all file decriptors (except for STDIN/STDOUT/STDERR)
134:     ios = Array.new(8192) {|i| IO.for_fd(i) rescue nil}.compact
135:     ios.each do |io|
136:       next if io.fileno < 3
137:       io.close
138:     end
139:   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 88
 88:   def daemonize(logfile_name = nil, app_name = nil)
 89:     # Split rand streams between spawning and daemonized process
 90:     srand 
 91:     
 92:      # Fork and exit from the parent
 93:     safefork and exit
 94: 
 95:     # Detach from the controlling terminal
 96:     unless sess_id = Process.setsid
 97:       raise Daemons.RuntimeException.new('cannot detach from controlling terminal')
 98:     end
 99: 
100:     # Prevent the possibility of acquiring a controlling terminal
101:     trap 'SIGHUP', 'IGNORE'
102:     exit if pid = safefork
103:     
104:     $0 = app_name if app_name
105:     
106:     # Release old working directory
107:     Dir.chdir "/"  
108: 
109:     close_io()
110: 
111:     redirect_io(logfile_name)
112:     
113:     return sess_id
114:   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 145
145:   def redirect_io(logfile_name)
146:     begin; STDIN.reopen "/dev/null"; rescue ::Exception; end       
147:      
148:     if logfile_name
149:       begin
150:         STDOUT.reopen logfile_name, "a" 
151:         File.chmod(0644, logfile_name)
152:         STDOUT.sync = true
153:       rescue ::Exception
154:         begin; STDOUT.reopen "/dev/null"; rescue ::Exception; end
155:       end
156:     else
157:       begin; STDOUT.reopen "/dev/null"; rescue ::Exception; end
158:     end
159:     
160:     begin; STDERR.reopen STDOUT; rescue ::Exception; end
161:     STDERR.sync = true
162:   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
 5:   def safefork
 6:     tryagain = true
 7: 
 8:     while tryagain
 9:       tryagain = false
10:       begin
11:         if pid = fork
12:           return pid
13:         end
14:       rescue Errno::EWOULDBLOCK
15:         sleep 5
16:         tryagain = true
17:       end
18:     end
19:   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
26:   def simulate(logfile_name = nil)
27:     # Release old working directory
28:     Dir.chdir "/"   
29: 
30:     close_io()
31: 
32:     # Free STDIN and point them somewhere sensible
33:     begin; STDIN.reopen "/dev/null"; rescue ::Exception; end       
34:   end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.