I have just had a lecture that sums reaping as:
Reaping
Performed by parent on terminated child (using wait or waitpid)
Parent is given exit status informaton
Kernel then deletes zombie child process
So I understand that reaping is done by calling wait or waitpid from the parent process after which the kernel deletes the zombie process. If this actually is the case, that reaping is done only when calling wait or waitpid, why do the child processes actually go away after returning in theor entry function - I mean that indeed does seem as if the child processes have been reaped and thus no resources are wasted even though the parent process may not be waiting.
So is "reaping" only possible when calling wait or waitpid? Is processes are "reaped" as long as they return and exit from their entry function (which I assume all processes do) - what is the point of talking about "reaping" as if it was something special?
The child process does not fully "go away" when it exits. It ceases to exist as a running process, and most/all of its resources (memory, open files, etc.) are released, but it still remains in the process table. It remains in the process table because that's where its exit status is stored, so that the parent can retrieve it by calling one of the wait variants. If the parent fails to call wait, the process table entry sticks around — and that's what makes it a "zombie".
I said that most/all of its resources are released, but the one resource that's definitely still consumed is that process table slot.
As long as the (dead) child's parent exists, the kernel doesn't know that the parent isn't going to call wait eventually, so the process table slot has to stay there, so that the eventual call to wait (if there is one) can return the proper exit status.
If the parent eventually exits (without ever calling wait), the child will be inherited by the grandparent, which is usually a "master" process like the shell, or init, that does routinely call wait and that will finally "reap" the poor young zombie.
So, yes, it really is true that the only way for the parent to properly "reap" the child is, just as was said in your lecture, to call one of the wait functions. (Or to exit, but that's not an option if the parent is long-running.)
Footnote: I said "the child will be inherited by the grandparent", but I think I was wrong, there. Under Unix and Linux, orphaned processes are generally always inherited by pid 1, aka init.
The purpose of the wait*() call is to allow the child process to report a status back to the parent process. When the child process exits, the operating system holds that status data in a little data structure until the parent reads it. Reaping in that sense is cleaning out that little data structure.
If the parent does not care about waiting for status from the child, the code could be written in a way to allow the parent to ignore the status, and so the reaping occurs semi-automatically. One way is to ignore the SIGCHLD signal.
Another way is to perform a double-fork to create a grandchild process instead. When doing this, the "parent" does a blocking wait() after a call to fork(). Then, the child performs another fork() to create the grandchild and then immediately exits, causing the parent to unblock. The grandchild now does the real work, and is automatically reaped by the init process.
Related
I have just had a lecture that sums reaping as:
Reaping
Performed by parent on terminated child (using wait or waitpid)
Parent is given exit status informaton
Kernel then deletes zombie child process
So I understand that reaping is done by calling wait or waitpid from the parent process after which the kernel deletes the zombie process. If this actually is the case, that reaping is done only when calling wait or waitpid, why do the child processes actually go away after returning in theor entry function - I mean that indeed does seem as if the child processes have been reaped and thus no resources are wasted even though the parent process may not be waiting.
So is "reaping" only possible when calling wait or waitpid? Is processes are "reaped" as long as they return and exit from their entry function (which I assume all processes do) - what is the point of talking about "reaping" as if it was something special?
The child process does not fully "go away" when it exits. It ceases to exist as a running process, and most/all of its resources (memory, open files, etc.) are released, but it still remains in the process table. It remains in the process table because that's where its exit status is stored, so that the parent can retrieve it by calling one of the wait variants. If the parent fails to call wait, the process table entry sticks around — and that's what makes it a "zombie".
I said that most/all of its resources are released, but the one resource that's definitely still consumed is that process table slot.
As long as the (dead) child's parent exists, the kernel doesn't know that the parent isn't going to call wait eventually, so the process table slot has to stay there, so that the eventual call to wait (if there is one) can return the proper exit status.
If the parent eventually exits (without ever calling wait), the child will be inherited by the grandparent, which is usually a "master" process like the shell, or init, that does routinely call wait and that will finally "reap" the poor young zombie.
So, yes, it really is true that the only way for the parent to properly "reap" the child is, just as was said in your lecture, to call one of the wait functions. (Or to exit, but that's not an option if the parent is long-running.)
Footnote: I said "the child will be inherited by the grandparent", but I think I was wrong, there. Under Unix and Linux, orphaned processes are generally always inherited by pid 1, aka init.
The purpose of the wait*() call is to allow the child process to report a status back to the parent process. When the child process exits, the operating system holds that status data in a little data structure until the parent reads it. Reaping in that sense is cleaning out that little data structure.
If the parent does not care about waiting for status from the child, the code could be written in a way to allow the parent to ignore the status, and so the reaping occurs semi-automatically. One way is to ignore the SIGCHLD signal.
Another way is to perform a double-fork to create a grandchild process instead. When doing this, the "parent" does a blocking wait() after a call to fork(). Then, the child performs another fork() to create the grandchild and then immediately exits, causing the parent to unblock. The grandchild now does the real work, and is automatically reaped by the init process.
I am learning the wait() method in C. And I know that it blocks the parent process until one of its child processes terminates. But what if the kernel decides to schedule the child first and the child process terminates before parent can call the wait()? Is that the parent will wait there forever(without other interrupts) since it can not observe the return of a child?
In the photo, if the execution sequence is: fork --> HC --> exit -->HP-->wait, then the situation I describe will happen.
No, the parent will not wait forever.
The documentation on wait states:
All of these system calls are used to wait for state changes in a
child of the calling process, and obtain information about the child
whose state has changed. A state change is considered to be: the
child terminated; the child was stopped by a signal; or the child was
resumed by a signal. In the case of a terminated child, performing a
wait allows the system to release the resources associated with the
child; if a wait is not performed, then the terminated child remains
in a "zombie" state .
If a child has already changed state, then these calls return immediately.
But what if the kernel decides to schedule the child first and the
child process terminates before parent can call the wait()?
It is a pretty possible case. If one of the wait family functions is used by the parent or signal(SIGCHLD, SIG_IGN); is called explicitly before forking, it does not turn the child into a zombie even if the parent process is preempted(=not permitted to use CPU at that time).
Moreover, the need of wait or signal-ignorance mentioned is to clean process's unused datas. While using one of the methods, the kernel is told that the child(ren) process is not used anymore. So, you can cleanup unused system resources.
I was trying to write a basic multiprocessing tcp-server, which forks a process for every new accept().
I don't need the parent process to wait on the child processes. I have come across two solutions- forking twice and daemonising.
What's the difference between the two?
Which is more suitable in this scenario?
What are the factors that are to be kept in mind for choosing one amongst these?
There is a subtle difference.
Forking twice: Intermediate child process can't become a zombie provided it has exited and has been waited for by Parent. Grandchild can't become a zombie either as it's parent (intermediate child process) has exited, so grandchild is an orphan. The orphan(grandchild) gets inherited by init and if it exits now, it is the responsibility of the system to clean it up. In this way, the parent process is releived of the responsibility of waiting to collect the exit status signal from child and also the parent can be busy doing some other work. This also enables the child to run for long time so that a shorttime parent need not wait for that amount of time.
Daemon: This is for programs wishing to detach themselves from the controlling terminal and run in the background as system daemons. Has no controlling terminal.
The decision of approach depends on the requirement/scenario in hand.
You do need the parent process to (eventually) wait() for each of its child processes, else the children will hang around until the parent exits. This is a form of resource leak.
Forking twice, with the intermediate process exiting immediately after forking, allows the original process to collect the child immediately (via wait()), and makes the grandchild process an orphan, which the system has responsibility for cleaning up. This is one way to avoid accumulating zombie processes. The grandchild remains in the same process group (and thus the same session) as the original process.
Daemonizing serves a somewhat different purpose. It puts the resulting (child) process in a new session (and new process group) with no controlling terminal. The same effect can be achieved by forking once, with the parent immediately calling _exit() and the child calling setsid().
A system service daemonizes to escape the session in which it was launched, so as not to be shut down when that session ends. This has little to do with multiprocessing, but a lot to do with process management. A process double-forks to avoid process management duties for the (grand)child processes; this has both multiprocessing and process management aspects.
Note, too, that double-forking doesn't just pass off process-management responsibilty, it also gives up process-management ability. Whether that's a good trade-off is situation-dependent.
In C language,I have a child thread(using pthreads),
Is there any way to restrict this child, so that we can't call fork inside this thread?
If we write fork inside, program should not compile.
I can also have a child process instead of child thread, as long as it cannot fork further.
Basically how can I have a child process or child thread, which cannot fork a process any further.
You can always try to play games with pthread_atfork: http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_atfork.html
Basically, you can use pthread_atfork() to install a "child" callback which always calls exit(). This way, your threads may still fork, but the forked process will exit immediately, so no harm will be done (and only a minimal overhead incurred).
With processes it may be somewhat more complicated. Linux allows you to limit a number of processes per user (so called RLIMIT_NPROC when set with setrlimit()). When this limit is reached, no further forks are possible for a given user id. Thus, you can create a parent process with a CAP_SETUID capability and a dummy user, having the RLIMIT_NPROC set to 1. This way, you can fork from parent, change the child uid to that of the "limited" user you've created in advance and drop the CAP_SETUID capability. At this point, child will have no possible way to fork itself.
kill - does it kill the process right away?
I found my answer and I set up a signal handler for SIGCHLD and introduced wait in that handler. That way, whenever parent process kills a child process, this handler is called and it calls wait to reap the child. - motive is to clear process table entry.
I am still seeing some child processes going for a few seconds even without its parent process dying. - how is this possible?
I am seeing this via ps. Precisely ps -o user,pid,ppid,command -ax and greping for parent process, child process and defunct.
A process goes defunct (zombie) immediately upon exiting (from a signal, call to exit, return from main, whatever). It stays zombie until wait'd on by its parent.
So, all processes at least briefly become zombies upon exit.
If the parent process takes a bit (because it was doing other work, or just because the scheduler hasn't given it CPU time yet) before calling wait, then you'll see the zombie for a bit. If the parent never calls wait, then when it eventually exits, init (pid 1) will adopt its zombied children, and call wait on them.
A child process goes defunct (becomes a zombie) only when its parent process hasn't died and hasn't yet waited for it. If the original parent died, then the child's parent becomes process ID 1, and that process's main task is to wait for its (inherited) children to die and remove them from the process list, so that they are not zombies. (Note: an orphaned child, or a daemon, is automatically inherited by PID 1; it does not get assigned to grandparents or great-grandparents up the hierarchy of processes.)
Between the time that the child dies and the parent collects the exit information via wait() (or waitpid(), or waitid() or any of the other variants), it is a zombie in the process list, shown as defunct by ps.
But to answer your question's title:
Yes, a process can go defunct without its parent dying.
(And it can only go defunct if its parent has not died.)