Skip to content →

Creating and Killing Processes in Linux

In computer science, a program refers to a set of instructions for the CPU (central processing unit) to execute. In Linux, a process is simply the name for a program that’s being executed. In this post we will look at how processes are created and how we can communicate with them.

Creation

When the computer boots up, the kernel (the ‘middle man’ between the operating system and the CPU) loads a program called init (or systemd) into memory and it begins executing; this is the first process.

From here on, processes are created by duplicating an existing process. This is known as a fork. The fork() system call asks the kernel to essentially copy the existing process and give the new process some space in memory. The original process is now referred to as the parent, and the duplicate becomes the child.

Each process has a unique PID (process identification number). The number 1 is reserved for init/systemd and you’ll often see processes assigned PIDs from 2 through 32,768, but they are not necessarily assigned in sequential order.

Let’s look at a C program that utilizes fork()to create a new process, getpid() and getppid() to display the PID of the child and parent processes, and wait() to control the flow of execution:

int main(void)
{
pid_t child;
int status; printf("I am the parent, my PID is %d\n", getpid());
printf("My parent's PID is %d\n", getppid());
printf("I am going to create a new process...\n"); child = fork(); if (child == -1)
{
// fork() returns -1 on failure
printf("fork() failed.");
return (-1);
}
else if (child == 0)
{
// fork() returns 0 to the child process
printf("I am the child, my PID is %d\n", getpid());
printf("My parent's PID is %d\n", getppid());
}
else
{
// fork() returns the PID of the child to the parent
wait(&status); // wait for the child process to finish...
printf("I am the parent, my PID is still %d\n", getpid());
}
return (0);
}

Output:

I am the parent, my PID is 26407
My parent's PID is 2040
I am going to create a new process...
I am the child, my PID is 26408
My parent's PID is 26407
I am the parent, my PID is still 26407

Note that getppid() in the child process returns the same value as getpid() in the parent process.

When this program finishes executing, the child and parent processes terminate and the flow of execution goes back to the where the program was invoked (e.g. the shell). If you ran this program from a Bash shell, like I did, you can use echo $$ to display the PID of the current Bash process.

Notice how the parent PID in our C program is the same as our Bash PID. This means that Bash forked a new process to execute our C program and waited for it to finish, just like we did in our C program. Once it terminated, the flow of execution returned back to Bash (the parent process).


Now let’s see what programs are currently being executed on our system.

We will use the ps command with some additional options that provide detailed information about the processes running on our system. The option -a lists processes of all users on the system, -u gives us details about the processes, and -x lists processes that run unobtrusively in the background (these are known as daemons and usually end with a d, like systemd).

output from ps aux. there are about 100 lines below this. each one a process.

Sometimes the output of ps aux can be overwhelming and we want to narrow down the list of processes. We can use pgrep to lookup ones that match a specific pattern of text. For example, pgrep -l chrome will search processes metadata for the pattern ‘chrome’, then display the PIDs of those processes along with the program’s name.

i have a lot of tabs open.

Now that we know how processes are created and how we can view running processes on our system, let’s see how we can control them.

kill is a shell builtin command that is used to send a signal to a process. By default, that signal is SIGTERM (for terminate). If we wanted to terminate one of our chrome processes we can invoke kill with the PID as an argument.

kill SIGTERM resulting in terminating a chrome tab

If we want to terminate all processes that match the pattern ‘slack’, for example, we can use pkill slack.

Some processes will receive the SIGTERM signal from kill, and handle it in a way where the process doesn’t actually terminate. For example, here is a program that uses trap to respond to kill:

#!/usr/bin/env bashwhile true; do
echo "my PID is $$"
trap "echo YOU CANNOT TERMINATE ME" SIGTERM
sleep 2 # for demo purposes
done
the SIGTERM signal does not terminate this program if there is a trap

If you want to be sure you are terminating a process you must use SIGKILL or SIGSTOP. These are the only two signals that cannot be ignored by trap. All of the signals can be displayed using kill -l and they have corresponding numbers that can be used instead of the all-caps words. For example kill -15 is the same command as kill -TERM.

Here I will use the same program as above, but use the -KILL flag to force termination:

-KILL for a forceful kill that cannot be ignored

Kill sounds like a violent word, but it’s not always used for signaling death sentences. SIGSTOP is a signal used for stopping a process, which can later be resumed by using the fg (foreground) command.

Here is the same program being stopped and continued:

stopping and continuing processes with kill -STOP

Conclusion

  • Processes are running instances of programs.
  • They are creating by duplicating an existing process (forking)
  • They each have a unique PID
  • We can use kill to send signals to them

Published in Journal