1

(I understand there are some existing questions on SO about the same topic and I have read top answers. Those answers are good but I still have something unclear.) Recently I came across a piece of Python for creating daemon process in Unix system: sample code And the piece I want to talk about:

def daemonize(self):
    """
    do the UNIX double-fork magic, see Stevens' "Advanced
    Programming in the UNIX Environment" for details (ISBN 0201563177)
    http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
    """
    try:
            pid = os.fork()
            if pid > 0:
                    # exit first parent
                    sys.exit(0)
    except OSError, e:
            sys.stderr.write("fork #1 failed: %d (%s)\n" % (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
                    sys.exit(0)
    except OSError, e:
            sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
            sys.exit(1)

    # redirect standard file descriptors
    sys.stdout.flush()
    sys.stderr.flush()
    si = file(self.stdin, 'r')
    so = file(self.stdout, 'a+')
    se = file(self.stderr, 'a+', 0)
    os.dup2(si.fileno(), sys.stdin.fileno())
    os.dup2(so.fileno(), sys.stdout.fileno())
    os.dup2(se.fileno(), sys.stderr.fileno())

    # write pidfile
    atexit.register(self.delpid)
    pid = str(os.getpid())
    file(self.pidfile,'w+').write("%s\n" % pid)

So the process is:

  1. Create a fork of current process and kill parent process. So in this case forked process 1 is an orphan now.
  2. decouple from parent environment--why do we do this? does that mean by setting sid of forked process 1, we can isolate the forked process? at this point, forked process 1 has its own process group and session(equals to its pid), which means it is an session leader, which means it is possible to acquire a new control terminal.
  3. fork again and kill forked process 1. forked process 2 now is also an orphan. and it is definitely not a session leader(forked process 1 was). and it does not share anything with the original parent process environment.
  4. do in/out/err redirection.

So is my understanding correct about the process of creating a daemon process? Also some people mentioned "this can prevent zombie processes" in SO question, why is this piece of code even related to zombie process? Parent will be killed so that the process is monitored by init, is not that what "daemon" means?

Some people also mention that forking once should give us a good daemon process already. Any example for this? Any example(system) under which fork once may not just work as a good daemon?

Community
  • 1
  • 1
Junchao Gu
  • 1,815
  • 6
  • 27
  • 43
  • 1
    Possible duplicate of [What is the reason for performing a double fork when creating a daemon?](http://stackoverflow.com/questions/881388/what-is-the-reason-for-performing-a-double-fork-when-creating-a-daemon) – Zaur Nasibov Feb 29 '16 at 07:16
  • I did mention that question in my question and I have read top 3 answers under that question. They are good answers but I still have something unclear, which is included in my question already – Junchao Gu Feb 29 '16 at 09:43
  • Some of the answers in the linked question, also explain that double forking, is only required if the parent process is expected to live longer than the child (thus leaving the child as a zombie in the parent's process table). – Dunes Feb 29 '16 at 11:40

1 Answers1

2

A process being part of same session means when bash receives SIGHUP when you disconnect over ssh, it terminates all the processes in the session. Default SIGHUP handler also terminates process. To avoid this you want to create a new session.

Additionally, TTY is a somewhat old concept, which through the years has picked up a huge history and loads of corner cases intended for interactivity, but are counterproductive when running daemons, because you do not want the kernel to send random signals to your non-interactive daemon process when something TTY related happens.


So ... you do not want to be a member of TTY session and you do not want to be a session leader, because those get signalled.

That's why you start a daemon: you run python1, this process forks, you get python1 and python2. Python2 starts new session and forks, so you get python3.

Setsid in python2 ensures python3 is not connected to python1 session, and fork in python2 is needed because python2 is still a session leader.

Python3 will then not receive any TTY related signals and won't be killed by SIGHUP when you disconnect or whatever TTY related stuff happens on the box.

hruske
  • 2,205
  • 19
  • 27