If you send a signal to a process, that process gets killed. I wonder how the rumor that killing a process also kills other processes got started, it seems particularly counter-intuitive.
There are, however, ways to kill more than one process. But you won't be sending a signal to one process. You can kill a whole process group by sending a signal to -1234 where 1234 is the PGID (process group ID), which is the PID of the process group leader. When you run a pipeline, the whole pipeline starts out as a process group (the applications may change this by calling setpgid
or setpgrp
).
When you start processes in the background (foo &
), they are in their own process group. Process groups are used to manage access to the terminal; normally only the foreground process group has access to the terminal. The background jobs remain in the same session, but there's no facility to kill a whole session or even to enumerate the process groups or processes in a session, so that doesn't help much.
When you close a terminal, the kernel sends the signal SIGHUP
to all processes that have it as their controlling terminal. These processes form a session, but not all sessions have a controlling terminal. For your project, one possibility is therefore to start all the processes in their own terminal, created by script, screen, etc. Kill the terminal emulator process to kill the contained processes (assuming they haven't seceded with setsid
).
You can provide more isolation by running the processes as their own user, who doesn't do anything else. Then it's easy to kill all the processes: run kill
(the system call or the utility) as that user and use -1 as the PID argument to kill, meaning “all of that user's processes”.
You can provide even more isolation, but with considerably more setup by running the contained processes in an actual container.
Sending kill -9 to a process doesn't require the process' cooperation (like handling a signal), it just kills it off.
You're presuming that because some signals can be caught and ignored they all involve cooperation. But as per man 2 signal
, "the signals SIGKILL and SIGSTOP cannot be caught or ignored". SIGTERM can be caught, which is why plain kill
is not always effective – generally this means something in the process's handler has gone awry.1
If a process doesn't (or can't) define a handler for a given signal, the kernel performs a default action. In the case of SIGTERM and SIGKILL, this is to terminate the process (unless its PID is 1; the kernel will not terminate init
)2 meaning its file handles are closed, its memory returned to the system pool, its parent receives SIGCHILD, its orphan children are inherited by init, etc., just as if it had called exit
(see man 2 exit
). The process no longer exists – unless it ends up as a zombie, in which case it is still listed in the kernel's process table with some information; that happens when its parent does not wait
and deal with this information properly. However, zombie processes no longer have any memory allocated to them and hence cannot continue to execute.
Is there something like a global table in memory where Linux keeps references to all resources taken up by a process and when I "kill" a process Linux simply goes through that table and frees the resources one by one?
I think that's accurate enough. Physical memory is tracked by page (one page usually equalling a 4 KB chunk) and those pages are taken from and returned to a global pool. It's a little more complicated in that some freed pages are cached in case the data they contain is required again (that is, data which was read from a still existing file).
Manpages talk about "signals" but surely that's just an abstraction.
Sure, all signals are an abstraction. They're conceptual, just like "processes". I'm playing semantics a bit, but if you mean SIGKILL is qualitatively different than SIGTERM, then yes and no. Yes in the sense that it can't be caught, but no in the sense that they are both signals. By analogy, an apple is not an orange but apples and oranges are, according to a preconceived definition, both fruit. SIGKILL seems more abstract since you can't catch it, but it is still a signal. Here's an example of SIGTERM handling, I'm sure you've seen these before:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
void sighandler (int signum, siginfo_t *info, void *context) {
fprintf (
stderr,
"Received %d from pid %u, uid %u.\n",
info->si_signo,
info->si_pid,
info->si_uid
);
}
int main (void) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = sighandler;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGTERM, &sa, NULL);
while (1) sleep(10);
return 0;
}
This process will just sleep forever. You can run it in a terminal and send it SIGTERM with kill
. It spits out stuff like:
Received 15 from pid 25331, uid 1066.
1066 is my UID. The PID will be that of the shell from which kill
is executed, or the PID of kill if you fork it (kill 25309 & echo $?
).
Again, there's no point in setting a handler for SIGKILL because it won't work.3 If I kill -9 25309
the process will terminate. But that's still a signal; the kernel has the information about who sent the signal, what kind of signal it is, etc.
1. If you haven't looked at the list of possible signals, see kill -l
.
2. Another exception, as Tim Post mentions below, applies to processes in uninterruptible sleep. These can't be woken up until the underlying issue is resolved, and so have ALL signals (including SIGKILL) deferred for the duration. A process can't create that situation on purpose, however.
3. This doesn't mean using kill -9
is a better thing to do in practice. My example handler is a bad one in the sense that it doesn't lead to exit()
. The real purpose of a SIGTERM handler is to give the process a chance to do things like clean up temporary files, then exit voluntarily. If you use kill -9
, it doesn't get this chance, so only do that if the "exit voluntarily" part seems to have failed.
Best Answer
There are a number of signals whose default disposition is to terminate the process. The ultimate termination signal is SIGKILL since it cannot be handled and the process has no choice but to die. This however also means that if you send it, the process is deprived of an opportunity to clean up. Therefore, good manners require to send a signal like SIGTERM that can be handled first and only if the process does not exit after some time send it SIGKILL.
Note that SIGINT and SIGQUIT are not good candidates for arbitrary process termination. Due to the fact that they can be generated from terminal's keyboard, many applications use them for special purposes. For example, python interpreter uses SIGINT to generate
KeyboardInterrupt
exception (also in interactive python sessions where it simply returns to the prompt) and JVM uses SIGQUIT to dump stack traces. SIGINT and SIGQUIT do remain effective for most standard command-line utilities likefind
orcat
.During system shutdown, most UNIX and Linux systems send SIGTERM to all process, followed by 5 seconds wait, followed by SIGKILL. This is the recommended way to safely shut down an arbitrary process.
Note also that even SIGKILL may not terminate a process stuck in an uninterruptible wait until the process wakes up.