6

I know os.setsid() is to change the process(forked) group id to itself, but why we need it?

I can see some answer from Google is: To keep the child process running while the parent process exit.

But according to my test below, without os.setsid() the child process won't exit as well even if the parent process exit(or being killed). So why we need to add os.setsid()? Thanks.

import os
import time
import sys

mainPid = os.getpid()
print("Main Pid: %s" % mainPid)

pid = os.fork()

if pid > 0:
    time.sleep(3)
    print("Main process quit")
    sys.exit(0)

#os.setsid()

for x in range(1, 10):
    print("spid: %s, ppid: %s pgid: %s" % (os.getpid(), os.getppid(), os.getpgid(0)))
    time.sleep(1)
Edwin
  • 71
  • 1
  • 1
  • 3
  • The answer is something really confusing about ttys and shell job control. Even I don't understand it fully, and I'm quite a tty nerd. – o11c Aug 28 '17 at 04:19
  • 1
    If you aren't exiting the login shell that is the process group leader the `os.setsid()` will not make much difference. For example you can use `setsid` when you `ssh` to a host to launch a command you don't want terminating when you exit your ssh session (an alternative would be `nohup`) – AChampion Aug 28 '17 at 04:25
  • setsid creates a new session id for the command you run using it, so that it does not depend on your shell session. If the shell session is closed the other command will continue to run. Obviously, any output will have to be thrown away or stored in a log,file,database etc if you wish to check it at a later date. Nohup would be your other option. – Rolf of Saxony Aug 28 '17 at 04:38
  • `Main_Python_Process >> Your_Process` Can you kill your_process without killing main_python_process ? How to give your process control to `OS` ? – dsgdfg Aug 28 '17 at 06:16
  • @AChampion Thanks for the reply, I just run the command 'python3.3 above_example.py' and then exit the ssh session, the script exit as well immediately, but when I added '>/dev/null' to the command, it keep running after I exit the ssh session. This can also be reproduced by the above python code, if I remove the print line in for loop(or redirect the stdout/stderr to a file), the script keep running, otherwise the script quit after exit the ssh session. It seems just need to make sure there's no output to stdout, the script will keep running. – Edwin Aug 28 '17 at 06:56
  • @AChampion So I am still not clear why setsid or os.setsid(in Python) is needed as this command were not involved in all above experiments. I did add setsid before the shell command and use os.setsid() in the script, but all behave same way with or without setsid. – Edwin Aug 28 '17 at 06:56
  • @dsgdfg The Mian_Python_Process will exit itself as expected, and then the OS will get the control of the forked process. Just not sure the use of setsid as the script behave same with or without it. Thanks. – Edwin Aug 28 '17 at 07:08

3 Answers3

4

Calling setsid is usually one of the steps a process goes through when becoming a so called daemon process. (We are talking about Linux/Unix OS).

With setsid the association with the controlling terminal breaks. This means that the process will be NOT affected by a logout.

There are other way how to survive a logout, but the purpose of this 'daemonizing' process is to create a background process as independent from the outside world as possible.

That's why all inherited descriptors are closed; cwd is set to an appropriate directory, often the root directory; and the process leaves the session it was started from.

A double fork approach is generally recommended. At each fork the parent exits and the child continues. Actually nothing changes except the PID, but that's exactly what is needed here.

First fork before the setsid makes sure the process is not a process group leader. That is required for a succesfull setsid.

The second fork after the setsid makes sure that a new association with a controlling terminal won't be started merely by opening a terminal device.


NOTE: when a daemon process is started from systemd, the systemd can arrange everything described above so the process does not have to.

VPfB
  • 14,927
  • 6
  • 41
  • 75
1

In some cases, the child process will be able to continue running even after the parent exits, but this is not foolproof. The child will also exit when the parent exits in some situations.

As of Python 3.2, you can use subprocess.Popen() and pass start_new_session=True to accomplish fully detach the child process from the parent.

The docs state:

If start_new_session is true the setsid() system call will be made in the child process prior to the execution of the subprocess. (POSIX only)

https://docs.python.org/3/library/subprocess.html#subprocess.Popen

Bernard
  • 2,118
  • 2
  • 10
  • 9
1

Well, double fork to daemonize is a good example. However, It's better to understand what is process group and session.

  • Session ID (SID)

This is just the PID of the session leader. If PID == SID, then this process is a session leader.

Sessions and process groups are just ways to treat a number of related processes as a unit. All the members of a process group always belong to the same session, but a session may have multiple process groups.

Normally, a shell will be a session leader, and every pipeline executed by that shell will be a process group. This is to make it easy to kill the children of a shell when it exits. (See exit(3) for the gory details.)

Basically, if you log into a machine, your shell starts a session. If you want to keep your process running even when you log out, you should start a new session for the child.

The difference with double forked process is that you can still attach a control terminal to that process since it's a session leader, whereas the daemon process created by double fork can not be attached to the terminal anymore.

Izana
  • 2,537
  • 27
  • 33