Wikipedia says "A child process that terminates but is never waited on by its parent becomes a zombie process." I run this program:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid, ppid;
printf("Hello World1\n");
pid=fork();
if(pid==0)
{
exit(0);
}
else
{
while(1)
{
printf("I am the parent\n");
printf("The PID of parent is %d\n",getpid());
printf("The PID of parent of parent is %d\n",getppid());
sleep(2);
}
}
}
This creates a zombie process, but I can't understand why a zombie process is created here?
The output of the program is
Hello World1
I am the parent
The PID of parent is 3267
The PID of parent of parent is 2456
I am the parent
The PID of parent is 3267
The PID of parent of parent is 2456
I am the parent
....
.....
But why is it that the "child process terminates but is not waited on by its parent" in this case?
In your code, zombie is created on exit(0) (comment with arrow below):
pid=fork();
if (pid==0) {
exit(0); // <--- zombie is created on here
} else {
// some parent code ...
}
Why? Because you never waited on it. When something calls waitpid(pid), it returns postmortem information about process, like its exit code. Unfortunately, when process exited, kernel cannot just dispose of this process entry, or return code will be lost. So it waits for somebody to wait on it, and leaves this process entry around even if it does not really occupy any memory except for entry in process table - this is exactly what is called zombie.
You have few options to avoid creating zombies:
Add waitpid() somewhere in the parent process. For example, doing this will help:
pid=fork();
if (pid==0) {
exit(0);
} else {
waitpid(pid); // <--- this call reaps zombie
// some parent code ...
}
Perform double fork() to obtain grandchild and exit in child while grandchild is still alive. Grandchildren will be automatically adopted by init if their parent (our child) dies, which means if grandchild dies, it will be automatically waited on by init. In other words, you need to do something like this:
pid=fork();
if (pid==0) {
// child
if (fork()==0) {
// grandchild
sleep(1); // sleep a bit to let child die first
exit(0); // grandchild exits, no zombie (adopted by init)
}
exit(0); // child dies first
} else {
waitpid(pid); // still need to wait on child to avoid it zombified
// some parent code ...
}
Explicitly ignore SIGCHLD signal in parent. When child dies, parent gets sent SIGCHLD signal which lets it react on children death. You can call waitpid() upon receiving this signal, or you can install explicit ignore signal handler (using signal() or sigaction()), which will make sure that child does not become zombie. In other words, something like this:
signal(SIGCHLD, SIG_IGN); // <-- ignore child fate, don't let it become zombie
pid=fork();
if (pid==0) {
exit(0); // <--- zombie should NOT be created here
} else {
// some parent code ...
}
Related
This question already has answers here:
Creating a daemon in Linux
(9 answers)
Closed 5 years ago.
I expect the following code on ubuntu linux to create a daemon process which is child process of systemd and keeps printing "do something".
#include <unistd.h>
#include <stdlib.h>
int main()
{
int pid1, pid2;
int status;
if (pid1 = fork()) {
waitpid(pid1, &status, NULL);
}
else if (!pid1) {
if (pid2 = fork()) {
// use exit. return sometimes stop forking
exit(0);
}
else if (!pid2) {
while(1) {
sleep(1);
puts("do something");
}
}
else {
perror("error occured");
return -1;
}
}
else {
perror("error occured");
return -1;
}
while(1) {
sleep(1);
puts("parent do something.");
}
}
But when I interrupt the parent process, its generated daemon also terminates. The daemon only left alive when I run the code on background. Why is it like this?
Daemon alive when I run on background.
$ ./a.out &
parent do something.
do something
parent do something.
do something
(ctrl + c)
do something
do something
do something
Daemon terminates when I run not on background.
$ ./a.out
parent do something.
do something
parent do something.
do something
(ctrl + c)
// not printing anymore
$
When you run on foreground the interrupt signals generated by the terminal go to the group (parent and child). There is more info about this in the following unix exchange answer.
When running on background the process is not listening to the interrupt signals of the terminal. So pressing ctrl+c has no effect at all.
Suppose I have 10 child processes which are moved to their own process group by setpgid(0,0) just before the exec. (Each child also has children which are also in their own process group.)
My foreground process gets ctrl-c SIGINT signal and I want to propagate it to the all child processes (all children are in different group). How to do that?
hope that quick draft better explain my problem.
void handler(int signal) {
// resend SIGINT to all childs but childs are in different pgid
}
int main(int argc, char* argv[]){
struct sigaction sa;
sa.sa_handler = &handler;
sigaction(SIGINT, &sa, NULL);
pid_t pid[SIZE];
int i = 0;
// if argv is ge 2;
for (;i < SIZE; i++) // SIZE is number of the elements in argv
{
pid[i] = fork();
if(pid[i] == 0)
{
setpgid(0,0);
// execv self here but with one less element in argv;
}
}
while(1){}; // infinity loop (waits for ctrl-c from foreground process)
// prints to the terminal pid and pgid
// waits here for all childs to finish and then close self
}
What about forwarding the signal in the signal handler of main process, manually. Maybe you can provide some code snippet to clarify the situation you're in.
void signalHandler(int signum)
{
kill(child_pid,signum);
//other stuff
}
I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
for(int i=0;i<3;i++)
{
int cpid=fork();
if(cpid==0)
printf("I am a child with id %d, and my parent is %d\n",getpid(),getppid());
else
printf("I am a parent with id %d\n",getpid());
}
}
I am trying to form a process tree. The output is:
I am a parent with id 9494
I am a parent with id 9494
I am a child with id 9495, and my parent is 9494
I am a parent with id 9494
I am a child with id 9496, and my parent is 9494
I am a parent with id 9495
I am a parent with id 9496
I am a parent with id 9495
I am a child with id 9498, and my parent is 9495
I am a parent with id 9498
I am a child with id 9499, and my parent is 3004
I am a child with id 9497, and my parent is 3004
I am a child with id 9500, and my parent is 3004
I am a child with id 9501, and my parent is 3004
I cannot figure out where is the process with id 3004 coming in. How many total processes are created as a result of this code? What will be the final process tree? I am beginner.
I'll help with the mystery of process 3004. The rest should be reasonably easy to figure out on your own (you might want to add cpid to the second printf() to help with that).
I am a child with id 9499, and my parent is 3004
What happened here is that the original parent of process 9499 had died before 9499 had a chance to call getppid(). When the parent of a process dies, that process gets re-parented. In your case, the new parent's pid is 3004. This process is not part of the process tree created by your program (it probably sits somewhere above it in the overall process tree), so you don't see a "I am a parent with id" for it.
Here is some relevant reading: process re-parenting: controlling who is the new parent.
Try this piece of code.
The output of this code will explain alot more things to you. Some of the processes print their respective printf function after their parent process died. These processes(orphan process) are adopted by some other processes. That could be the reason for a peculiar pid being printed by printf function. Also, there is a race-condition between creation of processes and printing of their respective pid which can be seen in the output of the code below.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
printf("Main\n");
for(int i=0;i<3;i++) {
printf("Loop index - %d and pid is - %d\n", i, getpid());
int cpid=fork();
if(cpid==0)
printf("I am a child with id %d, and my parent is %d with loop index - %d\n",getpid(),getppid(), i);
else
printf("I am a parent with id %d and with loop index - %d\n",getpid(), i);
}
printf("Terminated - %d\n", getpid());
return 0;
}
What is actually meant by cleaning up of child processes after it has ended?
In the book Advanced Linux Programming, there is a section on cleaning child processes asynchronously by handling SIGCHLD signal. This signal is sent to the parent process after the termination of child process.
sig_atomic_t child_exit_status;
void clean_up_child_process (int signal_number)
{
/* Clean up the child process. */
int status;
wait (&status);
/* Store its exit status in a global variable.
child_exit_status = status;
}
*/
int main ()
{
/* Handle SIGCHLD by calling clean_up_child_process. */
struct sigaction sigchld_action;
memset (&sigchld_action, 0, sizeof (sigchld_action));
sigchld_action.sa_handler = &clean_up_child_process;
sigaction (SIGCHLD, &sigchld_action, NULL);
/* Now do things, including forking a child process.
/* ... */
*/
return 0;
}
After catching the signal, the signal handler does nothing except storing the exit status in a global variable. So in this context what is meant by cleaning up of child processes?
I try write program, which realize next idea:
After start, program using fork() and:
parent process stopped on function wait() (for waiting death child process);
child process use prctl(PR_SET_PDEATHSIG, SIGHUP), and setup signal handler (It's helps detect parent death);
After death any process, program use fork() again.
void forking_process() {
pid_t id;
printf("forking_process is called!\n");
if (id = fork()) {
parent_process_operation();
} else {
child_process_operation();
}
}
void parent_process_operation() {
int status = 0;
printf("It's parent process! Pid = %d\n", (int)getpid());
pid_t chid = wait(&status);
printf("Terminated child process with PID = %d\n", chid);
inform_about_parent_death(status);
}
void child_process_operation() {
printf("It's child process! pid = %d, ppid = %d\n",
(int)getpid(), (int)getppid());
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = inform_about_parent_death;
if (sigaction(SIGHUP, &sa, NULL))
fprintf(stderr, "sigaction error\n");
prctl(PR_SET_PDEATHSIG, SIGHUP);
while(1) {
printf("."); fflush(stdout);
sleep(1);
}
}
void inform_about_parent_death(int i) {
printf("Process is dead. Restart!\n");
forking_process();
}
int main (void) {
forking_process();
return EXIT_SUCCESS;
}
If I run this application, and in another terminal kill child process - then will create child process.
If I kill the parent process once, - signal handler started and call fork().
If I again kill the parent process, - signal handler not responded.
That is - prctl() in first process work, but prctl() in second child process don't work.
Why it is happen? How I can correct it's program?