#99 entering pidfile context in child and not in parent
Closed: Invalid by arekm. Opened by arekm.

pidfile handling seems to be really weird in python daemon (or my understanding of its idea is wrong)

It seems to be creating lock (entering pidfile context) in child while I would be expecting it to be created in parent, before fork (and only passed to child to keep it active and to be able to release it on context exit).

Why in parent? To be able to immediately see if it's already locked (in case of trying to start daemon again) before even starting child.

(not working) example, run two in parallel:

import lockfile
import daemon
import daemon.pidfile
import sys
import time
pidfilename = "/tmp/xx"
pidfile = daemon.pidfile.TimeoutPIDLockFile(pidfilename)
try:
    with daemon.DaemonContext(stdout=sys.stdout, stderr=sys.stderr, pidfile=pidfile):
        time.sleep(60)
except lockfile.AlreadyLocked as e:
    print("daemon is already running")
    sys.exit(1)
else:
    print("nothing was running earlier")

expected result - getting lockfile.AlreadyLocked in parent
actual result - exception is done in child

What's the point of having it in child - no idea. (Almost) every daemon I know acts on pidfile before forking.


On 04-Mar-2025, Arkadiusz Miśkiewicz wrote:

pidfile handling seems to be really weird in python daemon (or my
understanding of its idea is wrong)

The sequence of steps for a program to become a daemon process, is a matter
of long standing convention. Though no formal standard exists, you can read
the SystemD manual page ‘daemon(7)’ for a comprehensive description of the
procedure to create a so-called “SysV style daemon” that ‘python-daemon’
implements https://www.man7.org/linux/man-pages/man7/daemon.7.html.

It seems to be creating lock (entering pidfile context) in child while I
would be expecting it to be created in parent, before fork (and only
passed to child to keep it active and to be able to release it on context
exit).

What leads you to believe that; do you have a canonical description of the
procedure that specifies that?

My sources indicate the convention is to handle creation of the PID file
within the actual daemon process (the child process from the ‘fork’ call).

One reason for this is that the PID is not known until the child process
exists.

Another is that creation and writing of the PID file is the correct way to
avoid a race condition: the file creation is only attempted when we know
the child process exists, and creating the PID file is done only to write
the PID value into it.

You can see, in the referenced manual page, that the double ‘fork’ (steps
5–7) occur before “In the daemon process, write the daemon PID (as returned
by getpid()) to a PID file” (step 12). This is the sequence implemented by
‘python-daemon’.

But the major justification is: This is part of the conventional definition
of the “become a daemon process” procedure, and existing daemon
implementations now depend on this procedure happening in precisely the
specified order.

Thanks for explanation.

Metadata Update from @arekm:
- Issue close_status updated to: Invalid
- Issue status updated to: Closed (was: Open)

Metadata