2

I am trying to help a user at AskUbuntu with the following question,

Exiting the terminal vs Closing the terminal

Context:-

I am running a process in bash with & appended i.e in background mode. The process has a while(1) i.e it will run forever. My bash is parent and my process becomes the child. I want to learn how Kernel handles the child when parent is terminated.

Observations:-

  1. If I exit the terminal (using exit command from the terminal), /lib/systemd/systemd --user becomes the parent process of the child
  2. If I kill the terminal process (using kill) from another terminal, same result as above
  3. If I close the terminal using cross icon, child process gets terminated too

Question:-

How is closing different from killing/exiting?

I have written an answer, but feel that I do not really understand what is happening, and I think that several of you who help here at Unix & Linux know better than I and can explain what is happening.

So please help us understand, by chipping in and write an answer (replacing my attempt at AskUbuntu).

2 Answers 2

4

The answer to 1 is that systemd --user adopts the orphan child (i.e. plays the role of pid 1 = init) because it has become a "subreaper" by calling prctl(PR_SET_CHILD_SUBREAPER, 1) before spawning its children. This is a Linux extension.

The answer to 3 is that it depends on the terminal emulator. They don't all work the same.

But generally, the difference between 1,2 and 3 is that in the latter case bash will get a SIGHUP signal [1] and will resend it to its children, causing the background process to die:

The shell [i.e. bash] exits by default upon receipt of a SIGHUP. Before exiting, an interactive shell resends the SIGHUP to all jobs, running or stopped. Stopped jobs are sent SIGCONT to ensure that they receive the SIGHUP.

This is a bash extension; not all the shells are resending the SIGHUP signal. Specifically, dash (the /bin/sh on Ubuntu) does no such thing.


But the background process can get a SIGHUP signal even in the case of 1, if it has a stopped process in its process group (simulating a terminal emulator with script):

$ script -q /dev/null -c /bin/bash
$ sh -c 'sleep 1 & kill -STOP $!; echo $$; while sleep 1; do :; done' &
[1] 3317
$ 3317

$ exit
exit
$ ps 3317
  PID TTY      STAT   TIME COMMAND
    # 3317 is dead.

The stopped (not sleeping) sleep process has taken down its parent process with it. If you leave out the sleep 1 & kill -STOP $! part, it will survive.

Unlike the previous one, this is a standard feature of the operating system, not something specific to bash or other shell.

[1] bash will receive a SIGHUP signal because it's in the foreground process group, and the terminal emulator has either destroyed the pseudo-terminal (causing the kernel to send the SIGHUP) or has itself sent the SIGHUP explicitly.

3
  • Thanks for explaining case 3. Can you also explain [better] why the background process is not stopped in cases 1 and 2, when there is no stopped process. After all, the terminal is closed.
    – sudodus
    Oct 15, 2021 at 13:31
  • Thanks again. Your answer and the other one together help me understand :-)
    – sudodus
    Oct 15, 2021 at 13:44
  • Please stop removing useful content from the site!
    – terdon
    Dec 30, 2021 at 14:14
1

A children must always have a parent (and every process has a parent PID).

In the first two cases, you kill the parent, so your process will have an invalid parent ID. Unix (and Posix) prescribes that init will adopt such processes (so the process with PID 1, which now it is often systemd), and such process get a signal (so it know it should adopt the new children, or maybe just kill it). This is also the reason init (and so systemd) is important: it can see if important process are killed or orphaned, and it can take actions).

The third case is more interesting. Note: in such case you are not killing the terminal, you are just telling the terminal to exit, so terminal has time to clean up it stuffs.

So now we have other kind of process, controlling groups and job control. Complex topic: the terminal will stop the terminal part (input processing and how to draw characters), but so the terminal (now usually a pasudoterminal, and for sure a pseudo terminal in x) will send SIGHUP to such processes, to tell them that the other side hang up. Usually this is equivalent to a kill to all processes in such control group. programs may tell the terminal to ignore the signal, or to handle such signal for a better exit (often a reset of screen). (nohup utility may be used to keep the process running also in case of a SIGHUP signal).

So the difference: 1 and 2 kill the parent which cannot sent SIGHUP to children so PID 1 takes care of them (note: and it may kill it, if stdin and stdout are not more available, but this depend on the parenting). In 3 the terminal exit nicely and notify the children that the other side hang-up, so they must handle it smoothly.

4
  • Thanks. I think I understand now :-)
    – sudodus
    Oct 15, 2021 at 13:44
  • firefox & and evince & continue to work happily after exit from bash, but are closed if the terminal window is closed (by pressing the x icon). Is this by intention or just happens to work like that because they have their own GUIs?
    – sudodus
    Oct 15, 2021 at 14:03
  • 1
    @muru: right. I edited the answer. Thank you Oct 16, 2021 at 15:49
  • 1
    @sudodus: & it is just about process control. The programs remain to the shell process group (which can e.g. bring to foreground with command fg. You have two possibilities: you demonize the program (so you request a new control group for your children), or you can try with nohup firefox & (possibly you should redirect stdout and stderr e.d. to /dev/null). Oct 16, 2021 at 15:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.