poky/bitbake/lib/bb/daemonize.py
Richard Purdie 9ed748a542 bitbake: daemonize: Always print any remaning UI events at exit
If there are events in the UI queue we want to print them regardless of
whether we're handling an exception or something like SystemExit.

This improves error messages for some other failure cases where currently
no logging would get printed and leave the user confused as to what went
wrong.

(Bitbake rev: 76c4f2c20216719736766e8ae7d089ccd061b71b)

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2017-08-03 11:14:13 +01:00

83 lines
3.1 KiB
Python

"""
Python Daemonizing helper
Originally based on code Copyright (C) 2005 Chad J. Schroeder but now heavily modified
to allow a function to be daemonized and return for bitbake use by Richard Purdie
"""
import os
import sys
import io
import traceback
def createDaemon(function, logfile):
"""
Detach a process from the controlling terminal and run it in the
background as a daemon, returning control to the caller.
"""
try:
# Fork a child process so the parent can exit. This returns control to
# the command-line or shell. It also guarantees that the child will not
# be a process group leader, since the child receives a new process ID
# and inherits the parent's process group ID. This step is required
# to insure that the next call to os.setsid is successful.
pid = os.fork()
except OSError as e:
raise Exception("%s [%d]" % (e.strerror, e.errno))
if (pid == 0): # The first child.
# To become the session leader of this new session and the process group
# leader of the new process group, we call os.setsid(). The process is
# also guaranteed not to have a controlling terminal.
os.setsid()
try:
# Fork a second child and exit immediately to prevent zombies. This
# causes the second child process to be orphaned, making the init
# process responsible for its cleanup. And, since the first child is
# a session leader without a controlling terminal, it's possible for
# it to acquire one by opening a terminal in the future (System V-
# based systems). This second fork guarantees that the child is no
# longer a session leader, preventing the daemon from ever acquiring
# a controlling terminal.
pid = os.fork() # Fork a second child.
except OSError as e:
raise Exception("%s [%d]" % (e.strerror, e.errno))
if (pid != 0):
# Parent (the first child) of the second child.
# exit() or _exit()?
# _exit is like exit(), but it doesn't call any functions registered
# with atexit (and on_exit) or any registered signal handlers. It also
# closes any open file descriptors. Using exit() may cause all stdio
# streams to be flushed twice and any temporary files may be unexpectedly
# removed. It's therefore recommended that child branches of a fork()
# and the parent branch(es) of a daemon use _exit().
os._exit(0)
else:
os.waitpid(pid, 0)
return
# The second child.
# Replace standard fds with our own
si = open('/dev/null', 'r')
os.dup2(si.fileno(), sys.stdin.fileno())
try:
so = open(logfile, 'a+')
se = so
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
except io.UnsupportedOperation:
sys.stdout = open(logfile, 'a+')
sys.stderr = sys.stdout
try:
function()
except Exception as e:
traceback.print_exc()
finally:
bb.event.print_ui_queue()
os._exit(0)