How to Kill a Child Process in C
-
Use the
SIGKILL
Signal to Terminate a Child Process in C -
Use the
SIGTERM
Signal to Terminate a Child Process in C
This article will demonstrate multiple methods about how to kill a child process in C.
Use the SIGKILL
Signal to Terminate a Child Process in C
There are multiple signals designed to terminate a process upon its delivery, but sending the SIGKILL
signal is the most powerful and sure method to do it. Generally, a program can register special functions called signal handlers that are invoked automatically once the corresponding signal is delivered to the program. The user implements the handler function code that usually conducts some cleanup work for the program. Apart from function handlers, there can be default actions on delivered signals like blocking and ignoring. Although, the SIGKILL
signal can’t be ignored, blocked, or handled by the given function. Thus, this method should be the last resort when trying to terminate a process.
The SIGKILL
signal can be sent with a kill
system call. Note though, the SIGTERM
handler registered in the following code sample can’t catch the delivered SIGKILL
, and it immediately kills the given child process.
The following program spawns a child process and registers the SIGTERM
handler in it. Then, the child process executes an infinite loop unless the signal is delivered, which flips the while
expression variable. Consequently, the SIGKILL
signal delivered by the parent does not invoke the handler and terminates the child process instantly.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
volatile sig_atomic_t shutdown_flag = 1;
void cleanupRoutine(int signal_number) { shutdown_flag = 0; }
int main(void) {
int wstatus;
pid_t c_pid = fork();
if (c_pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (c_pid == 0) {
printf("printed from child process - %d\n", getpid());
int count = 0;
struct sigaction sigterm_action;
memset(&sigterm_action, 0, sizeof(sigterm_action));
sigterm_action.sa_handler = &cleanupRoutine;
sigterm_action.sa_flags = 0;
// Mask other signals from interrupting SIGTERM handler
if (sigfillset(&sigterm_action.sa_mask) != 0) {
perror("sigfillset");
exit(EXIT_FAILURE);
}
// Register SIGTERM handler
if (sigaction(SIGTERM, &sigterm_action, NULL) != 0) {
perror("sigaction SIGTERM");
exit(EXIT_FAILURE);
}
while (shutdown_flag) {
count += 1;
}
printf("count = %d\n", count);
exit(EXIT_SUCCESS);
} else {
printf("printed from parent process - %d\n", getpid());
int ret;
sleep(5);
ret = kill(c_pid, SIGKILL);
if (ret == -1) {
perror("kill");
exit(EXIT_FAILURE);
}
if (waitpid(c_pid, &wstatus, WUNTRACED | WCONTINUED) == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
}
exit(EXIT_SUCCESS);
}
Use the SIGTERM
Signal to Terminate a Child Process in C
Alternatively, a child process can be terminated using SIGTERM
signal, which can be handled by the program. The next code sample repeats the previous program implementation except that it substitutes the SIGKILL
signal with SIGTERM
. The sigfillset
function is used to prevent other signals from interrupting the registered handler function execution. The handler code modifies the global sig_atomic_t
type variable that stops the while
loop in the child process and prints the count
variable’s value. Mind though, it’s always better to use the sigaction
call above the signal
function when registering the handlers, as the latter is not specified in detail by the POSIX standard.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
volatile sig_atomic_t shutdown_flag = 1;
void cleanupRoutine(int signal_number) { shutdown_flag = 0; }
int main(void) {
int wstatus;
pid_t c_pid = fork();
if (c_pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (c_pid == 0) {
printf("printed from child process - %d\n", getpid());
int count = 0;
struct sigaction sigterm_action;
memset(&sigterm_action, 0, sizeof(sigterm_action));
sigterm_action.sa_handler = &cleanupRoutine;
sigterm_action.sa_flags = 0;
// Mask other signals from interrupting SIGTERM handler
if (sigfillset(&sigterm_action.sa_mask) != 0) {
perror("sigfillset");
exit(EXIT_FAILURE);
}
// Register SIGTERM handler
if (sigaction(SIGTERM, &sigterm_action, NULL) != 0) {
perror("sigaction SIGTERM");
exit(EXIT_FAILURE);
}
while (shutdown_flag) {
count += 1;
}
printf("count = %d\n", count);
exit(EXIT_SUCCESS);
} else {
printf("printed from parent process - %d\n", getpid());
int ret;
sleep(5);
ret = kill(c_pid, SIGTERM);
if (ret == -1) {
perror("kill");
exit(EXIT_FAILURE);
}
if (waitpid(c_pid, &wstatus, WUNTRACED | WCONTINUED) == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
}
exit(EXIT_SUCCESS);
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook