We will make zombies using the T-virus developed by the pharmaceutical company Umbrella. That's a joke, and I'll show you how to create, avoid, and make Buddhahood processes in C.
A zombie process is a child process in which the parent process leaves the child process alone and cannot be terminated indefinitely.
[vagrant@vagrant-centos65 ~]$ cat /etc/redhat-release
CentOS release 6.5 (Final)
zombie.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int
main(int argc, char *argv[])
{
pid_t pid;
//Argument check
if (argc != 3) {
fprintf(stderr, "Usage: %s <command> <arg>\n", argv[0]);
exit(1);
}
//fork to create a child process
//In the process after fork, two processes, a parent process and a child process, are executed at the same time.
pid = fork();
if (pid < 0) {
fprintf(stderr, "fork(2) failed\n");
exit(1);
}
//The return value of the fork of the child process is 0
if (pid == 0) { /*What the child process does*/
execl(argv[1], argv[1], argv[2], NULL);
/* execl()Will not return if successful, so everything will fail if returned*/
perror(argv[1]);
exit(99);
}
//The return value of the fork of the parent process is the process ID of the child process
else { /*What the parent process does*/
//Zombie survival time is 30 seconds
//I set it to 30 seconds here, but while(1)In the case of an infinite loop such as, zombies will always exist
sleep(30);
printf("child (PID=%d) finished;\n", pid);
exit(0);
}
}
Argument 1: Full path of the command to be executed (this time / bin / echo
)
Argument 2: Parameter for the command of argument 1 (this time This is zombie
)
If you execute as below, the prompt will not return for 30 seconds, and you will not be able to confirm the existence of zombies on the same terminal. (If you want to check the zombies by raising another terminal, you can use the following method.)
[vagrant@vagrant-centos65 tmp]$ gcc -o zombie ./zombie.c
[vagrant@vagrant-centos65 tmp]$ ./zombie /bin/echo "This is zombie"
This is zombie //→ In this state, you have to wait for 30 seconds, you cannot do other work, etc.
child (PID=24579) finished; //→ Displayed after 30 seconds
[vagrant@vagrant-centos65 tmp]$
Therefore, add & at the end of the command as shown below and execute it in the background process.
We also confirm that zombies exist with the ps command during the 30 seconds that zombies exist.
You can confirm that it is a zombie because defunct
is displayed in the result of the ps command.
[vagrant@vagrant-centos65 tmp]$ ./zombie /bin/echo "This is zombie" &
[1] 24601
[vagrant@vagrant-centos65 tmp]$ This is zombie
//→ If you do not press enter, the prompt will not be returned, so press enter
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ ps aux | grep defunct | grep -v grep
vagrant 24602 0.0 0.0 0 0 pts/0 Z 23:06 0:00 [echo] <defunct>
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ child (PID=24602) finished; //→ Displayed after 30 seconds
//→ If you do not press enter, the prompt will not be returned, so press enter
[1]+ Done ./zombie /bin/echo "This is zombie"
[vagrant@vagrant-centos65 tmp]$
After forking, the parent process uses waitpid to catch the termination of the child process. It is the parent's responsibility to prevent zombies from occurring.
zombie_avoid1.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int
main(int argc, char *argv[])
{
pid_t pid;
//Argument check
if (argc != 3) {
fprintf(stderr, "Usage: %s <command> <arg>\n", argv[0]);
exit(1);
}
//fork to create a child process
//In the process after fork, two processes, a parent process and a child process, are executed at the same time.
pid = fork();
if (pid < 0) {
fprintf(stderr, "fork(2) failed\n");
exit(1);
}
//The return value of the fork of the child process is 0
if (pid == 0) { /*What the child process does*/
execl(argv[1], argv[1], argv[2], NULL);
/* execl()Will not return if successful, so everything will fail if returned*/
perror(argv[1]);
exit(99);
}
//The return value of the fork of the parent process is the process ID of the child process
else { /*What the parent process does*/
int status;
waitpid(pid, &status, 0);
sleep(30);
printf("child (PID=%d) finished; ", pid);
if (WIFEXITED(status))
printf("exit, status=%d\n", WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("signal, sig=%d\n", WTERMSIG(status));
else
printf("abnormal exit\n");
exit(0);
}
}
You can confirm that the zombie does not exist with the ps command.
[vagrant@vagrant-centos65 tmp]$ gcc -o zombie_avoid1 ./zombie_avoid1.c
[vagrant@vagrant-centos65 tmp]$ ./zombie_avoid1 /bin/echo "This is zombie" &
[1] 24619
[vagrant@vagrant-centos65 tmp]$ This is zombie
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ ps aux | grep defunct | grep -v grep
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ child (PID=24620) finished; exit, status=0
[1]+ Done ./zombie_avoid1 /bin/echo "This is zombie"
[vagrant@vagrant-centos65 tmp]$
Create a child process from a parent process and a grandchild process from a child process. And by terminating the child process, the grandchild process does not become a zombie because the parent process from the grandchild process no longer exists. Make sure that the grandchild process still exists when the parent and child processes terminate.
process | processの終了時間 |
---|---|
Parent process | Finish after 30 seconds |
Child process | Immediate end |
Grandchild process | Finish after 60 seconds |
zombie_avoid2.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int
main(int argc, char *argv[])
{
pid_t pid;
//Argument check
if (argc != 3) {
fprintf(stderr, "Usage: %s <command> <arg>\n", argv[0]);
exit(1);
}
//fork to create a child process
//In the process after fork, two processes, a parent process and a child process, are executed at the same time.
pid = fork();
if (pid < 0) {
fprintf(stderr, "fork(2) failed\n");
exit(1);
}
//The return value of the fork of the child process is 0
if (pid == 0) { /*What the child process does*/
pid_t pid_child;
pid_child = fork();
if (pid_child < 0) {
fprintf(stderr, "child fork(2) failed\n");
exit(1);
}
if (pid_child == 0) { /*What the grandchild process does*/
execl(argv[1], argv[1], argv[2], NULL);
/* execl()Will not return if successful, so everything will fail if returned*/
perror(argv[1]);
exit(99);
} else { /*What the child process does*/
printf("grandchild (PID=%d) finished; ", pid_child);
exit(0);
}
}
//The return value of the fork of the parent process is the process ID of the child process
else { /*What the parent process does*/
int status;
waitpid(pid, &status, 0);
sleep(30);
printf("child (PID=%d) finished; ", pid);
if (WIFEXITED(status))
printf("exit, status=%d\n", WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("signal, sig=%d\n", WTERMSIG(status));
else
printf("abnormal exit\n");
exit(0);
}
}
This time I'm using sleep
instead of ʻecho` to check for the existence of grandchild processes.
[vagrant@vagrant-centos65 tmp]$ gcc -o zombie_avoid2 ./zombie_avoid2.c
[vagrant@vagrant-centos65 tmp]$ ./zombie_avoid2 /bin/sleep 60 &
[1] 25674
[vagrant@vagrant-centos65 tmp]$ grandchild (PID=25676) finished;
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$
//Zombies do not exist
[vagrant@vagrant-centos65 tmp]$ ps aux | grep defunct | grep -v grep
//Grandchild process exists
[vagrant@vagrant-centos65 tmp]$ ps aux | grep 25676 | grep -v grep
vagrant 25676 0.0 0.1 100924 620 pts/0 S 01:29 0:00 /bin/sleep 60
[vagrant@vagrant-centos65 tmp]$ child (PID=25675) finished; exit, status=0
[1]+ Done ./zombie_avoid2 /bin/sleep 60
[vagrant@vagrant-centos65 tmp]$
//The grandchild process still exists when the parent process terminates
[vagrant@vagrant-centos65 tmp]$ ps aux | grep 25676 | grep -v grep
vagrant 25676 0.0 0.1 100924 620 pts/0 S 01:29 0:00 /bin/sleep 60
[vagrant@vagrant-centos65 tmp]$
//The grandchild process also ends after 60 seconds
[vagrant@vagrant-centos65 tmp]$ ps aux | grep 25676 | grep -v grep
[vagrant@vagrant-centos65 tmp]$
zombie_avoid3.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
static void detach_children(void);
static void noop_handler(int sig);
int
main(int argc, char *argv[])
{
pid_t pid;
//Argument check
if (argc != 3) {
fprintf(stderr, "Usage: %s <command> <arg>\n", argv[0]);
exit(1);
}
detach_children();
//fork to create a child process
//In the process after fork, two processes, a parent process and a child process, are executed at the same time.
pid = fork();
if (pid < 0) {
fprintf(stderr, "fork(2) failed\n");
exit(1);
}
//The return value of the fork of the child process is 0
if (pid == 0) { /*What the child process does*/
execl(argv[1], argv[1], argv[2], NULL);
/* execl()Will not return if successful, so everything will fail if returned*/
perror(argv[1]);
exit(99);
}
//The return value of the fork of the parent process is the process ID of the child process
else { /*What the parent process does*/
printf("child (PID=%d) finished;\n", pid);
//Since the signal is caught in sleep, it loops infinitely in while
while(1);
exit(0);
}
}
static void
detach_children(void)
{
struct sigaction act;
act.sa_handler = noop_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART | SA_NOCLDWAIT;
if (sigaction(SIGCHLD, &act, NULL) < 0) {
printf("sigaction() failed: %s", strerror(errno));
}
}
static void
noop_handler(int sig)
{
;
}
[vagrant@vagrant-centos65 tmp]$ gcc -o zombie_avoid3 ./zombie_avoid3.c
[vagrant@vagrant-centos65 tmp]$ ./zombie_avoid3 /bin/echo "This is zombie" &
[1] 25895
[vagrant@vagrant-centos65 tmp]$ child (PID=25896) finished;
This is zombie
[vagrant@vagrant-centos65 tmp]$
//Zombies do not exist
[vagrant@vagrant-centos65 tmp]$ ps aux | grep defunct | grep -v grep
// zombie_avoid3 process exists
[vagrant@vagrant-centos65 tmp]$ ps aux | grep zombie_avoid3 | grep -v grep
vagrant 25895 102 0.0 3924 448 pts/0 R 02:42 0:13 ./zombie_avoid3 /bin/echo This is zombie
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ kill 25895
[vagrant@vagrant-centos65 tmp]$
[1]+ Terminated ./zombie_avoid3 /bin/echo "This is zombie"
[vagrant@vagrant-centos65 tmp]$
I will show you how to terminate the zombie process created in zombie.c
.
[vagrant@vagrant-centos65 tmp]$ ./zombie /bin/echo "This is zombie" &
[1] 25932
[vagrant@vagrant-centos65 tmp]$ This is zombie
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ ps aux | grep -e zombie -e defunct | grep -v grep
vagrant 25932 0.0 0.0 3920 372 pts/0 S 02:47 0:00 ./zombie /bin/echo This is zombie
vagrant 25933 0.0 0.0 0 0 pts/0 Z 02:47 0:00 [echo] <defunct>
[vagrant@vagrant-centos65 tmp]$
//Kill zombies
[vagrant@vagrant-centos65 tmp]$ kill 25933
//Killed a zombie, but the zombie exists
[vagrant@vagrant-centos65 tmp]$ ps aux | grep -e zombie -e defunct | grep -v grep
vagrant 25932 0.0 0.0 3920 372 pts/0 S 02:47 0:00 ./zombie /bin/echo This is zombie
vagrant 25933 0.0 0.0 0 0 pts/0 Z 02:47 0:00 [echo] <defunct>
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ child (PID=25933) finished;
[1]+ Done ./zombie /bin/echo "This is zombie"
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ ./zombie /bin/echo "This is zombie" &
[1] 25965
[vagrant@vagrant-centos65 tmp]$ This is zombie
[vagrant@vagrant-centos65 tmp]$
[vagrant@vagrant-centos65 tmp]$ ps aux | grep -e zombie -e defunct | grep -v grep
vagrant 25965 0.0 0.0 3920 372 pts/0 S 02:50 0:00 ./zombie /bin/echo This is zombie
vagrant 25966 0.0 0.0 0 0 pts/0 Z 02:50 0:00 [echo] <defunct>
[vagrant@vagrant-centos65 tmp]$
//Kill the parent process
[vagrant@vagrant-centos65 tmp]$ kill 25965
[vagrant@vagrant-centos65 tmp]$
[1]+ Terminated ./zombie /bin/echo "This is zombie"
[vagrant@vagrant-centos65 tmp]$
//There are no parent processes or zombies
[vagrant@vagrant-centos65 tmp]$ ps aux | grep -e zombie -e defunct | grep -v grep
[vagrant@vagrant-centos65 tmp]$
kill
.[Normal Linux programming 2nd edition: The royal road of gcc programming that can be learned from the mechanism of Linux](https://www.amazon.co.jp/%E3%81%B5%E3%81%A4%E3%81%86% E3% 81% AELinux% E3% 83% 97% E3% 83% AD% E3% 82% B0% E3% 83% A9% E3% 83% 9F% E3% 83% B3% E3% 82% B0-% E7 % AC% AC2% E7% 89% 88-Linux% E3% 81% AE% E4% BB% 95% E7% B5% 84% E3% 81% BF% E3% 81% 8B% E3% 82% 89% E5 % AD% A6% E3% 81% B9% E3% 82% 8Bgcc% E3% 83% 97% E3% 83% AD% E3% 82% B0% E3% 83% A9% E3% 83% 9F% E3% 83 % B3% E3% 82% B0% E3% 81% AE% E7% 8E% 8B% E9% 81% 93-% E9% 9D% 92% E6% 9C% A8-% E5% B3% B0% E9% 83 % 8E-ebook / dp / B075ST51Y5)
How to create a zombie process double fork to avoid zombie process
Recommended Posts