Zombie isn't really related to the others; it simply is a process that has terminated, but its parent process has not yet read its exit status with waitpid()
or similar. You shouldn't see these unless a process is buggy or stopped.
A daemon is a program that runs without a controlling terminal. Typically when you run the program, it fork()s
itself, and the parent exits so the shell thinks the command has finished, and the child process detaches from the terminal and escapes the login session. Since its parent process exited, its parent process ID becomes 1, which is traditionally the init
program, or these days, systemd
. This process makes sure to reap its children when they die so you don't end up overrun with zombies.
A process can be associated with a controlling terminal, which is where it normally gets its input from and sends its output to. The terminal also can send signals to processes attached to it, and identifies a process group as the foreground group. Processes that are in the foreground group are allowed to read input from the terminal, and are sent SIGINT and SIGSUSP signals when you press Ctrl-C and Ctrl-Z. Any process not in the foreground group that tries to read from the terminal is suspended with SIGTSTP.
The shell creates different process groups for each of the pipeline commands you ask it to run, and shifts which one is the foreground group to move jobs between the foreground and background. When you run a command, normally the shell makes a new process group and makes that group the foreground group. If you suffix it with an &
then the shell simply leaves the foreground group where it was and so the new group is in the background. Pressing Ctrl-Z sends SIGSUSP to the foreground group, which causes most commands to suspend, but instead of suspending, the shell changes the active foreground group back to itself so it can prompt you for a new command.
The bg
command sends SIGCONT to a process group so that it can resume running in the background after having been suspended with SIGSUSP. fg
changes the foreground group to one of the existing groups already running in the background, bringing it to the foreground.
fork()
off a copy of yourself, useexec()
in that copy to replace it with what you want to run, and usewait()
in the original instance of program (not the copy that ranexec()
). In the very, very short period of time between when the child exits and when thewait()
reaps that exit status (removing it from the process table and returning it to the caller), you have a zombie.