I am trying to understand how and does waitpid() using WNOHANG actually clean the resources of the child it's supposed to wait for?
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
printf("Hello from start\n");
int pid;
if((pid = fork()) == 0){
printf("Hello from child: %d\n", getpid());
printf("My parent PID is: %d\n", getppid());
}else if(pid > 0){
printf("Hello from parent: %d\n", getpid());
int status;
waitpid(pid, &status, WNOHANG);
}else{
perror("ERROR");
}
printf("Outside if statement, pid is: %d\n", getpid());
}
The output for child process for parent PID is: 1 meaning parent terminated and child was zombie passed to init process.
From what I understood WNOHANG in man description, it's supposed to return whether child process terminated at the time of testing it and let parent process continue on. I however thought that if parent was about to terminate before its child, it would wait for child to "clean it up". From this it seems that the parent just keeps on going and terminates without cleaning up.
What am I missing, and how to let parent continue its work but not let it terminate without waiting for child to terminate first?
Thanks!
I however thought that if parent was about to terminate before its child, it would wait for child to "clean it up".
That is not the case. The parent won't wait. Children of a process that terminates get reparented to process 1, and they will automatically get reaped when they terminate.
how to let parent continue its work but not let it terminate without waiting for child to terminate first?
work();
int status;
waitpid(pid, &status, 0);
Related
int main() {
pid_t pid;
printf("Parent: %d\n", getpid());
pid = fork();
if (pid == -1) {
perror("fork");
goto clean_up;
} else if (pid > 0) {
sleep(3);
} else {
printf("Child Parent: %d\n", getppid());
printf("Child: %d\n", getpid());
printf("Exiting...\n");
}
clean_up:
return 0;
}
I wanted to create zombie process on purpose (of course for experimenting/learning). After the child exits, the parent doesn't wait()s for the child. So, I'm expecting zombie to show up, in ps -ef | grep zombie.o. But for some reason it is not showing up. What could be the possible reasons?
When the parent exits, all its children (alive or zombie) are assigned PID 1 as their new parent. See the _exit(2) man page: " any children of the process are inherited by process 1".
PID 1 is normally the init daemon, and if it's working properly then it should always wait() for its children. So zombie children will be reaped immediately, and children that are still running will be reaped as soon as they exit.
If you want to create a long-lived zombie, the parent needs to remain alive but not calling wait().
I have the following example code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int main (){
printf("hello world (pid:%d)\n", (int)getpid());
int rc = fork();
if(rc < 0){ //fork failed; exit
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) { //child new process
printf("hello, i am child (pid:%d)\n", (int)getpid());
char *myargs[3];
myargs[0] = strdup("wc"); //program: "wc" (word count)
myargs[1] = strdup("p3.c"); //argument: file to count
myargs[2] = NULL; //marks end of array
execvp(myargs[0],myargs); //runs word count
printf("this shouldn't print out");
} else {//parent process
// int wc = wait(NULL);
// printf("hello, i am parent of %d (wc: %d) (pid: %d)\n", rc, wc, (int) getpid());
}
return 0;
}
So I have commented out the else statement (the arguments or the actions of the parent process. I was wondering what would happen, or would the outputs remain the same if the parent process does not have to wait for the child process? If so, why?
I was thinking, since the child process is its own independent process from the parent, the output would remain the same but is that the only reason why?
Some pointers would be nice, thanks!
This can be understood in two contexts.
Execution time of parent < execution time of child
Execution time of parent > execution time of child
In case 1, the parent process exits before the child and hence, the init process (pid 1) becomes the parent of the child; child process continues execution.
Normally, a child process (resources of child process) cannot be released until the parent process completes. In case 2, the child process is released only after the completion of parent process; till that time the child process becomes a zombie (defunct in ps -al command).
In this particular context, when the parent process has nothing to execute, the execution time of child > execution time of parent, which is nothing but execution time of parent < execution time of child. This is case 1. Hence, the parent process exits and init process becomes the parent of the child process.
Here is how my program articulates: there is a parent that forks a child and this child forks itself another child. So There is a parent, a child and a subchild (i.e. the parent of this subchild is the child).
The child execute a command with execlp(), let's say date to make it simple. The subchild do the same.
Of course the child forks the subchild before executing the command.
I am looking for the subchild to execute the command AFTER the child executed its own command. Moreover after the child and subchild executed their command, I would like the parent to continue its own process.
I have 2 problems:
I don't know how to make the parent to wait for the subchild execution
I can't make the subchild wait for the child execution (does the child lose its pid when using execlp?)
Here is my current implementation:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main (int argc, char **argv){
pid_t pid1, pid2;
pid1 = fork();
if (pid1 > 0)
{
int status;
// Wait child
printf("Parent waiting for child\n");
waitpid(pid1, &status, 0);
printf("Parent has waited child\n");
// Wait subchild
printf("Parent waiting for subchild\n");
// Wait sub-child here?
printf("Parent has waited subchild\n");
// End
printf("parent end\n");
}
else
{
pid2 = fork();
// Subchild
if (pid2 == 0) {
waitpid(getppid(), NULL, 0); // wait child? it doesn't work
execlp("/bin/date", "date", "+Subchild:\"%d-%m-%y\"", (char *) 0);
_exit(EXIT_FAILURE);
}
// Child
else {
execlp("/bin/date", "date", "+Child:\"%d-%m-%y\"", (char *) 0);
_exit(EXIT_FAILURE);
}
}
return 0;
}
My two "problems" are line 21 and 33.
The output is the following:
Parent waiting for child
Subchild:"03-10-17"
Child:"03-10-17"
Parent has waited child
Parent waiting for subchild
Parent has waited subchild
parent end
The subchild executes itself as fast as it can... I resolved this by using shared variable but it felt like a workaround and I still had issues with the parent waiting for the subchild.
Thanks to #JonathanLeffler I could solve the problem by creating pipes. It took time since I didn't know how pipes work but in the end it was much more easier than I thought.
#DavidC.Rankin I read the documentation about the wait function but it doesn't seem to be of any help in that situation.
Thank you.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main ( void ) {
int pid, fpid, ppid;
fpid = fork();
printf ("fpid is is %d\n", fpid);
sleep(5);
if (fpid > 0) {
pid = getpid();
ppid = getppid();
printf ("\nThis is Parent. My pid %d. My parent's pid %d\n", pid, ppid);
} else if (fpid == 0) {
sleep(1);
pid = getpid();
ppid = getppid();
printf ("\nThis is Child. My pid %d. My parent'a pid %d\n", pid, ppid);
}
}
I think when the parent process ID is 1 it means that the parent process has been terminated, so the child process gets re-parented to 1 (init, the first process). Is there any reason why the parent process would be terminated?
Parent process doesn't wait (by means of wait(2)) for the child process to complete. So, if parent exits before the child (it becomes an orphan process), then child process will be re-parented (adopted) to init process whose process ID is usually 1. Thus the child process says its parent process ID is 1.
Note that the init process' ID isn't necessarily 1 on all systems. POSIX doesn't mandate any such thing.
Because the child sleeps, by the time it calls getppid(), its parent will have likely died and the child will have been reparented to the init process (pid == 1).
Been practicing with those system calls, but I stucked into this code:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
main()
{
pid_t pid;
switch(pid = fork())
{
case -1:
printf("fork failed");
break;
case 0: //first child
printf("\ni'm the first child, my pid is %d", getpid());
fflush(stdout);
break;
default: //parent
sleep(5); /** sleep is generating problems **/
printf("\ni'm the parent process, my pid is %d", getpid());
printf("\ngenerating a new child");
fflush(stdout);
switch(pid = fork())
{
case -1:
printf("fork failed");
break;
case 0: //second child
printf("\nhere i am, the second child, my pid is %d", getpid());
break;
default: //parent
wait((int *)0);
printf("\nback to parent, my pid is %d", getpid());
}
}
return 0;
}
The output I'm getting is:
i'm the first child, my pid is 6203
i'm the parent process, my pid is 6202
generating a new child
back to parent, my pid is 6202
Process returned 0 (0x0) execution time: 5.004 s
Press ENTER to continue
here i am, the second child, my pid is 6204
What I'm trying it's a simple print of these messages managing the timing via sleep().
I can't understand why the program is returning before printing the second child message.
The default case(the one right after the second fork) got printed before its child(second) acting on the output like he's ignoring its wait(). Its child therefore got printed after the process returns.
I wasn't able to figure out what's the problem. I've marked sleep() function since if I substitute it with wait((int *)0); the processes flux is working how it was designed to (anyhow, without any timing).
At this point I'm not sure anymore about process flux, or the sleep() usage (man pages wasn't that helpful, way too concise to be honest).
Actually, your call to wait works. It detects the end of the first child process and continues afterwards. If you do two consecutive calls to wait(), you will get the proper behaviour.
Updated test code :
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
main()
{
pid_t pid;
int status;
switch(pid = fork())
{
case -1:
printf("fork failed");
break;
case 0: //first child
printf("\ni'm the first child, my pid is %d", getpid());
fflush(stdout);
break;
default: //parent
sleep(5); /** sleep is generating problems **/
printf("\ni'm the parent process, my pid is %d", getpid());
printf("\ngenerating a new child");
fflush(stdout);
switch(pid = fork())
{
case -1:
printf("fork failed");
break;
case 0: //second child
printf("\nhere i am, the second child, my pid is %d", getpid());
break;
default: //parent
pid = wait(&status);
printf("\nParent detects process %d was done", pid);
pid = wait(&status);
printf("\nParent detects process %d was done", pid);
printf("\nback to parent, my pid is %d", getpid());
}
}
return 0;
}
Output :
i'm the first child, my pid is 30897
i'm the parent process, my pid is 30896
generating a new child
here i am, the second child, my pid is 30940
Parent detects process 30897 was done
Parent detects process 30940 was done
back to parent, my pid is 30896
The man page for wait says the following:
The wait() function shall suspend execution of the calling thread until status information for one of the terminated child processes of the calling process is available, or until delivery of a signal whose action is either to execute a signal-catching function or to terminate the process. If more than one thread is suspended in wait() or waitpid() awaiting termination of the same process, exactly one thread shall return the process status at the time of the target process termination.
Wait is returning because of the first child.