Why does this fork hang? - c

Why doesn't the program end? The child hangs after printing what it has to print. If the parent process slept instead of the child, It would have worked, but why is that? I have also tried calling exit at the end of each process, but with the same result. Do I always have to wait for the child to finish?
int main(){
int pid = fork();
char s[100] = "Hello";
if(pid > 0){
printf("FIRST PRINT IN PARENT: %s\n", s);
strcat(s, " - PARENT");
printf("SECOND PRINT IN PARENT: %s\n", s);
}
else if(pid == 0){
printf("IMMEDIATELY IN CHILD: %s\n", s);
sleep(2);
printf("AFTER 2 SCONDS IN CHILD: %s\n", s);
}
return 0;
}

When the parent exits it might send a signal (SIGHUP) to the child.
If it does, and if the child doesn't catch that signal, the child dies.
Historically, the default has been for a process to send SIGHUP to it's children when it exits. Nowadays, many Linux distributions don't send SIGHUP by default.
I tried your code on RHEL and the child process wasn't killed.
So the parent dies and control returns to the shell. The child continues and prints it's second output 2 seconds later.
If the child does receive a SIGHUP it won't hang. It dies, and the final string is never printed.
In Linux, you can turn on SIGHUP via the prctl system call:
#include <sys/prctl.h>
prctl(PR_SET_PDEATHSIG, SIGHUP);
Related question: how-to-make-child-process-die-after-parent-exits

The shell does give you the prompt back once its child process (i.e. the parent process in your code) exits. However,
it doesn't know about the child process your code started.
The source of problems you have observed is that your parent process doens't wait for its child.
Use wait(2) system call, such as wait(0);, in the parent process.
The general risk of not waiting for child process(es) is that you might end up with zombie processes; conversely, orphan processes (if you parent process exits first).

Related

fork: child process doesn't stay in an infinite loop

#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = fork();
printf("pid : %d\n", getpid());
if( pid == 0)
{
printf("child: pid : %d \n", getpid());
while(1);
}
else
{
printf("parent: pid : %d \n", getpid());
//while(1);
}
}
In the above code snippet inside if statement if we put while(1), it doesn't remains blocked and when enter key is pressed program is exited, but in case of parent if we put while(1), parent remains blocked until we give ctrl+c. Please clarify this behaviour of child.
In the above code snippet inside if statement if we put while(1), it doesn't remains blocked
The child process doesn't exit actually; it just becomes an orphan process because its parent exits. The orphaned chuld process will be adopted by the init process of your system. You can see it via ps command.
But if you put the while(1); in the parent process it remains blocked.
Basically whichever process has while(1); infinite loop, it's still running. When parent exits you get the prompt back and the child becomes orphan. But the child process is still running.
In general, you need to wait(2) for the child process in the parent process to reap child processes.

How to terminate a program from a child process?

I am trying to terminate my program which takes a line that is full of commands from a file and then process each command using execvp
However,Whenever I encounter quit, I want to immediately exit processing the commands and ignore all other commands that are coming after it.
I tried to do this the following way using exit()
for(int i =0;i < numOfCommands;i++)
{
childPid = fork();
if(childPid == 0)
{
if(execvp(commands[i].cmd[0],commands[i].cmd) == -1)
{
/*if(strcmp(commands[i].cmd[0],"quit"))
{
done = true;
return;
}*/
if(strcmp(commands[i].cmd[0],"quit")==0)
{
printf("Quit command found ! \n Quitting .");
done = true;
//return;
exit(0);
}
printf("Command %s is unknown \n", commands[i].cmd[0]);
}
}
else
{
//parent process
wait(&child_status);
}
}
}
And this happens inside of the child process, after forking of course. But the problem is that my program keeps processing the remaining commands that comes after quit before exiting the program !
You can use kill(2) to send a signal to the process group. You can do this in the parent or any of the children.
int kill(pid_t pid, int sig);
If pid equals 0, then sig is sent to every process in the process group of the calling process.
For example:
kill(0, SIGTERM);
I think a better way to deal with this is to check for the quit command in the parent process before forking the child.
But if you want to do it in the child, you can send a signal to the parent.
kill(getppid(), SIGUSR1);
The parent process will need to establish a signal handler for SIGUSR1 that cleans everything up and exits. Or you could send a signal like SIGINT, whose default action is to kill the process, but it's better to implement a clean exit.
Also, in your code, you should check for the quit command before calling execvp. Otherwise, if there's a quit program in the user's path, it will never match your built-in quit, since execvp will succeed and not return.

How do you kill zombie process using wait()

I have this code that requires a parent to fork 3 children.
How do you know (and) where to put the "wait()" statement to kill
zombie processes?
What is the command to view zombie processes if you have Linux
virtual box?
main(){
pid_t child;
printf("-----------------------------------\n");
about("Parent");
printf("Now .. Forking !!\n");
child = fork();
int i=0;
for (i=0; i<3; i++){
if (child < 0) {
perror ("Unable to fork");
break;
}
else if (child == 0){
printf ("creating child #%d\n", (i+1));
about ("Child");
break;
}
else{
child = fork();
}
}
}
void about(char * msg){
pid_t me;
pid_t oldone;
me = getpid();
oldone = getppid();
printf("***[%s] PID = %d PPID = %d.\n", msg, me, oldone);
}
How do you know (and) where to put the "wait()" statement to kill
zombie processes?
If your parent spawns only a small, fixed number of children; does not care when or whether they stop, resume, or finish; and itself exits quickly, then you do not need to use wait() or waitpid() to clean up the child processes. The init process (pid 1) takes responsibility for orphaned child processes, and will clean them up when they finish.
Under any other circumstances, however, you must wait() for child processes. Doing so frees up resources, ensures that the child has finished, and allows you to obtain the child's exit status. Via waitpid() you can also be notified when a child is stopped or resumed by a signal, if you so wish.
As for where to perform the wait,
You must ensure that only the parent wait()s.
You should wait at or before the earliest point where you need the child to have finished (but not before forking), OR
if you don't care when or whether the child finishes, but you need to clean up resources, then you can periodically call waitpid(-1, NULL, WNOHANG) to collect a zombie child if there is one, without blocking if there isn't any.
In particular, you must not wait() (unconditionally) immediately after fork()ing because parent and child run the same code. You must use the return value of fork() to determine whether you are in the child (return value == 0), or in the parent (any other return value). Furthermore, the parent must wait() only if forking was successful, in which case fork() returns the child's pid, which is always greater than zero. A return value less than zero indicates failure to fork.
Your program doesn't really need to wait() because it spawns exactly four (not three) children, then exits. However, if you wanted the parent to have at most one live child at any time, then you could write it like this:
int main() {
pid_t child;
int i;
printf("-----------------------------------\n");
about("Parent");
for (i = 0; i < 3; i++) {
printf("Now .. Forking !!\n");
child = fork();
if (child < 0) {
perror ("Unable to fork");
break;
} else if (child == 0) {
printf ("In child #%d\n", (i+1));
about ("Child");
break;
} else {
/* in parent */
if (waitpid(child, NULL, 0) < 0) {
perror("Failed to collect child process");
break;
}
}
}
return 0;
}
If the parent exits before one or more of its children, which can happen if it does not wait, then the child will thereafter see its parent process being pid 1.
Others have already answered how to get a zombie process list via th ps command. You may also be able to see zombies via top. With your original code you are unlikely to catch a glimpse of zombies, however, because the parent process exits very quickly, and init will then clean up the zombies it leaves behind.
How do you know (and) where to put the "wait()" statement to kill
zombie processes?
You can use wait() anywhere in the parent process, and when the child process terminates it'll be removed from the system. Where to put it is up to you, in your specific case you probably want to put it immediately after the child = fork(); line so that the parent process won't resume its execution until its child has exited.
What is the command to view zombie processes if you have Linux virtual box?
You can use the ps aux command to view all processes in the system (including zombie processes), and the STAT column will be equal to Z if the process is a zombie. An example output would be:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
daniel 1000 0.0 0.0 0 0 ?? Z 17:15 0:00 command
How do you know (and) where to put the "wait()" statement to kill
zombie processes?
You can register a signal handler for SIGCHLD that sets a global volatile sig_atomic_t flag = 0 variable to 1. Then, at some convenient place in your program, test whether flag is set to 1, and, if so, set it back to 0 and afterwards (for otherwise you might miss a signal) call waitpid(-1, NULL, WNOHANG) in a loop until it tells you that no more processes are to be waited for. Note that the signal will interrupt system calls with EINTR, which is a good condition to check for the value of flag. If you use an indefinitely blocking system call like select(), you might want to specify a timeout after which you check for flag, since otherwise you might miss a signal that was raised after your last waitpid() call but before entering the indefinitely blocking system call. An alternative to this kludge is to use pselect().
Use:
ps -e -opid,ppid,pgid,stat,etime,cmd | grep defunct
to see your zombies, also the ppid and pgid to see the parent ID and process group ID. The etime to see the elapsed (cpu) time your zombie has been alive. The parent ID is useful to send custom signals to the parent process.
If the parent process is right coded to catch and handle the SIGCHLD signal, and to what expected (i.e., wait/reap the zombies), then you can submit:
kill -CHLD <parent_pid>
to tell the parent to reap all their zombies.

Why is my parent process not waiting the second time? C/Unix

So, what I am trying to do is create a child process, have it execute execl and run ls. Then after ls is done, create another child process and have it run a cat command on a file. The second wait(pid) does not seem to wait for the second child process to complete before finishing. here is my code and output
#include <fcntl.h>
int main(){
int pid;
printf("In parent process, creating child now...\n");
pid = fork();
if (pid==0){
printf("Now in child process...\n");
execl("/bin/ls","ls","-l",(char*)0);
}
wait(pid);
printf("ls child process complete\n");
printf("in parent process\n");
printf("Creating another child process\n");
pid=fork();
if(pid==0){
execl("/bin/cat","cat","f1",(char*)0);
}
wait(pid);
return 0;
}
Here is my output
In parent process, creating child now...
Now in child process...
"Contents of ls"
ls child process complete
in parent process
creating another child process
[username#host ~]$ "Contents of file" *cursor*
the parent process seems to finish before the second child is complete. There is only 1 child existing at a time. The "Contents of file" are supposed to appear before the [username#host ~]$ prompt. I think i am misplacing a wait or wrong pid assignment or something. Thanks in advance!
The argument to wait() is not a PID. It's a pointer to an int where the exit status will be stored. You're passing an integer where a pointer is needed, which means:
The program might crash or corrupt some unrelated memory location as soon as you call wait. Its behavior after that point is unpredictable.
You need to enable more compiler warnings and pay attention to them.
Although the Cat process may have finished the disk cache may still be holding the results... Instead of waiting for cat to complete wait until the lock on the file is released.

Linux Fork: pid reuse

I wrote the following program to understand the way fork works when called without wait() or waitpid().
int main()
{
pid_t childpid;
int retval = 0;
int i;
while(1){
//usleep(1);
childpid = fork();
if (childpid >= 0)
{
i++;
if (childpid == 0)
{
exit(retval);
}
else
{
//printf("childpid is %d\n", childpid);
}
}
else
{
printf("total no. of processes created = %d\n", i);
perror("fork");
exit(0);
}
}
}
Here's the output I get->
total no. of processes created = 64901
fork: Cannot allocate memory
I expected the program to go on as I'm exiting the child process instantly and fork() should reuse the pids after pid > pid_max. Why doesn't this happen?
The exited child processes do remain in the process table as zombies. Zombie processes exist until their parent calls wait or waitpid to obtain their exit status. Also, the corresponding process id is kept, to prevent other newly created processes of duplicating it.
In your case, the process table becomes too large and the system rejects the creation of new processes.
Forking processes and then not retrieving their exit status can be regarded as a resource leak. When the parent exits, they will be adopted by the init process and then reaped, but if the parent stays alive for too long, there is no way for the system to just remove some of the zombies, because it is assumed that the parent should get interested in them at some point via wait or waitpid.
Child processes also hold some resource like memory. But they are not released because parent process can not process SIGCHLD signal, which will be sent by child processes when they exit.
Those child processes will become zombie.
You can use "ps -aux" to dump those fd.

Resources