3

Alright bear with me there seems to be some answers on google about that but I simply cannot get it.

I'm running it after two forks in a Django Celery environment. I don't know if these could have changed something but I assume they did not.

There is not much code to leave as a mighty

if __name__ == '__main__':
    os.setsid()

grants me the beautiful Operation not permitted

I'm running the latest stable Django, Debian, Celery and Python version.

Zulu
  • 8,765
  • 9
  • 49
  • 56
cp151
  • 189
  • 2
  • 17
  • Your example doesn't work because "setsid() fails if the calling process is already a process group leader" (from the description of "Operation not permitted" from the man page setsid(2)). That doesn't answer your question though, because after fork(2)ing you're no longer a process group leader. – Phillip Dec 11 '14 at 08:25

1 Answers1

3

Python's os.setsid() probably calls the underlying library call setsid(3).

The full ERRORS section in man 3 setsid is:

ERRORS
   EPERM  The  process group ID of any process equals the PID of the call-
          ing process.  Thus, in particular, setsid() fails if the calling
          process is already a process group leader.

IOW: the only cause for a setsid() failure, is when the calling process is already a process group leader. Ergo: you may ignore the failure. To verify that this is the case, compare what you get back from getpid() and getpgid() when os.setsid() fails:

#!/usr/bin/env python

import os
import errno

if __name__ == '__main__':
    try:
        os.setsid()
    except OSError, (err_no, err_message):
        print "os.setsid failed: errno=%d: %s" % (err_no, err_message)
        print "pid=%d  pgid=%d" % (os.getpid(), os.getpgid(0))

When I run the above I get:

os.setsid failed: errno=1: Operation not permitted
pid=17025  pgid=17025

Note that the process-id (pid) is equal to the process-group-id (pgid), meaning that this process is indeed already a process group leader.

P.S: Yes, it is a baffling feature of python to raise exceptions where a simple error return code would suffice to distinguish success from failure (just like the familiar Un*x libc APIs behave). This is unfortunately how the python system call interface is implemented, so you need to wrap many system calls with try: except ...: constructs to prevent python from aborting your code.

arielf
  • 5,802
  • 1
  • 36
  • 48