|I l@ve RuBoard|
6.8 Forking a Daemon Process on Unix
Credit: Jürgen Hermann
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( )
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梐 minor detail梚s 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).
|I l@ve RuBoard|