6.8 Forking a Daemon Process on Unix
Credit: Jürgen Hermann
6.8.1 Problem
You need to fork a daemon process on a Unix
or Unix-like system, and this, in turn, requires a certain precise
sequence of system calls.
6.8.2 Solution
Daemon processes must detach from their controlling terminal and
process group. This is not hard, but it does take some care:
import sys, os
def main( ):
""" An example daemon main routine; writes a datestamp to file
/tmp/daemon-log every 10 seconds.
"""
import time
f = open("/tmp/daemon-log", "w")
while 1:
f.write('%s\n' % time.ctime(time.time( )))
f.flush( )
time.sleep(10)
if _ _name_ _ == "_ _main_ _":
# Do the Unix double-fork magic; see Stevens's book "Advanced
# Programming in the UNIX Environment" (Addison-Wesley) for details
try:
pid = os.fork( )
if pid > 0:
# Exit first parent
sys.exit(0)
except OSError, e:
print >>sys.stderr, "fork #1 failed: %d (%s)" % (
e.errno, e.strerror)
sys.exit(1)
# Decouple from parent environment
os.chdir("/")
os.setsid( )
os.umask(0)
# Do second fork
try:
pid = os.fork( )
if pid > 0:
# Exit from second parent; print eventual PID before exiting
print "Daemon PID %d" % pid
sys.exit(0)
except OSError, e:
print >>sys.stderr, "fork #2 failed: %d (%s)" % (
e.errno, e.strerror)
sys.exit(1)
# Start the daemon main loop
main( )
6.8.3 Discussion
Forking a daemon on Unix requires a certain specific sequence of
system calls, which is explained in W. Richard
Steven's seminal book, Advanced
Programming in the Unix Environment (Addison-Wesley). We
need to fork twice, terminating each parent
process and letting only the grandchild of the original process run
the daemon's code. This allows us to decouple the
daemon process from the calling terminal, so that the daemon process
can keep running (typically as a server process without further user
interaction, like a web server, for example) even after the calling
terminal is closed. The only visible effect of this is that when you
run this script as a main script, you get your shell prompt back
immediately.
For all of the details about how and why this works in Unix and
Unix-like systems, see Stevens's book. Stevens gives
his examples in the C programming language, but since
Python's standard library exposes a full POSIX
interface, this can also be done in Python. Typical C code for a
daemon fork translates almost literally to Python; the only
difference you have to care about�a minor detail�is that
Python's
os.fork
does not return -1 on errors but throws an OSError
exception. Therefore, rather than testing for a less-than-zero return
code from fork, as we would in C, we run the
fork in the try clause of a
try/except statement, so that
we can catch the exception, should it happen, and print appropriate
diagnostics to standard error.
6.8.4 See Also
Documentation of the standard library module os in
the Library Reference; Unix manpages for the
fork, umask, and
setsid system calls; Advanced
Programming in the Unix Environment, by W. Richard Stevens
(Addison-Wesley, 1992).
|