Add better comments about how the daemonization logic works.
This commit is contained in:
parent
7af0acce68
commit
751b3222db
@ -19,27 +19,50 @@ proc daemonize*(pidfile, si, so, se: string, daemonMain: proc(): void): Pid =
|
||||
if fileExists(pidfile):
|
||||
raise newException(IOError, "pidfile " & pidfile & " already exists, daemon already running?")
|
||||
|
||||
# We're about to do a little dance to end up with a process that is
|
||||
# disconnected from the calling program's process group and is not a session
|
||||
# leader (a daemon process).
|
||||
#
|
||||
# Remember, after a call to fork the code is now running in two processes,
|
||||
# the parent process and the child process. So the returned PID will be a
|
||||
# positive value if we are still on the parent process, and represents the
|
||||
# PID of the newly created process. If we are on the newly created process,
|
||||
# the PID returned with be 0.
|
||||
|
||||
let pid1 = fork()
|
||||
|
||||
# Are we the child process?
|
||||
if pid1 == 0:
|
||||
# Yes, so let's get ready to execute the main code given to us. Note that
|
||||
# this child process will not actually live long. As part of our setup,
|
||||
# we're going to create a new process session, resulting in this child
|
||||
# process being the process group owner and session leader. We don't our
|
||||
# daemon process to be a session leader because that allows it to be
|
||||
# connected to a terminal. So after we've setup the new process group we
|
||||
# will fork again and actually run the logic we're daemonizing in the
|
||||
# grandchild process.
|
||||
|
||||
# Yes, so let's get ready to execute the main code given to us.
|
||||
# Ignore whatever the original working directory was.
|
||||
discard chdir("/")
|
||||
|
||||
# Create a new session to decouple us from the original terminal.
|
||||
discard setsid()
|
||||
|
||||
# Set the process file mode creation mask to 0000
|
||||
discard umask(0)
|
||||
|
||||
# Fork again... but I'm not sure why.
|
||||
# Fork again so the grandchild process will not be the session leader.
|
||||
let pid2 = fork()
|
||||
|
||||
# We don't need the intermediate process, so if we are not the child this
|
||||
# time, lets just quit
|
||||
# If we're still on the child process, we're done.
|
||||
if pid2 > 0: quit(QuitSuccess)
|
||||
|
||||
# If we are the grandchild let's set up our environment.
|
||||
# Otherwise, if we are the grandchild let's finish setting up our
|
||||
# environment.
|
||||
flushFile(stdout)
|
||||
flushFile(stderr)
|
||||
|
||||
# Setup our STDIN, STDERR, and STDOUT pipes (if given)
|
||||
if si.len > 0:
|
||||
fi = open(si, fmRead)
|
||||
discard dup2(getFileHandle(fi), getFileHandle(stdin))
|
||||
@ -52,17 +75,20 @@ proc daemonize*(pidfile, si, so, se: string, daemonMain: proc(): void): Pid =
|
||||
fe = open(se, fmAppend)
|
||||
discard dup2(getFileHandle(fe), getFileHandle(stderr))
|
||||
|
||||
# Keep a record of the PID filename in our process memory so we can
|
||||
# reference it in our cleanup hooks.
|
||||
pidFileInner = pidfile
|
||||
|
||||
# Add hooks to cleanup after ourselves when we're asked to die.
|
||||
signal(SIGINT, onStop)
|
||||
signal(SIGTERM, onStop)
|
||||
|
||||
# Find out what our actual PID is and save it
|
||||
# Find out what our actual PID is and save it to the PID file.
|
||||
let childPid = getpid()
|
||||
writeFile(pidfile, $childPid)
|
||||
|
||||
# Finally, execute our main
|
||||
# Finally, execute the logic given to us to daemonize
|
||||
daemonMain()
|
||||
|
||||
# If we're not the child proces, return the new PID of the daemonized process
|
||||
return pid1
|
||||
|
Loading…
x
Reference in New Issue
Block a user