what does kill exactly do?
I have a parent process which is creating 100 (as an example) child processes one after another. At the end of any child's job, I kill the child with kill(pid_of_child, SIGKILL) and I cannot see that in ps output. But if something goes wrong with the parent process and I exit from the parent process with exit(1) (at this point only 1 child is there - I can check tht in ps), at that point I see a lot of <defunct> processes whose ppid is pid of parent process.
How is that possible? did kill not kill the child processes entirely?
kill doesn't kill anything. It sends signals to the target process. SIGKILL is just a signal. Now, the standard action for SIGKILL -- the only action, actually, since SIGKILL can't be handled or ignored by a process -- is to exit, that's true.
The "<defunct>" process is a child that hasn't been reaped, meaning that the parent hasn't called wait() to retrieve the exit status of the child. Until the parent calls wait(), the defunct (or "zombie") process will hang around.
Whenever a process ends, no matter how it ends (kill or otherwise), it will stay in the kernel's process table until its parent process retrieves its exit status (with wait and friends). Leaving it in the process table avoids a number of nasty race conditions.
If your parent process has exited, the children should get reassigned to init, which periodically reaps its children.
Yes, SIGKILL terminates the process, but in any case (either normal exit or terminated), processes have an exit status, which needs to be kept around for potential readers - as such an entry in the process table may remain until this is done. See http://en.wikipedia.org/wiki/Zombie_process .
Related
I would like to have the same effect in my program as the bash(terminal) does when we kill it using SIGKILL. As we know that we cannot handle SIGKILL in our progams so when ever I kill my program its children are assigned to init process, there is no way to handle it so that I can kill all my child processes and then kill the parent itself. Though when ever we kill terminal all the process created through it are killed even if we kill our terminal by SIGKILL.
For this I did some research and found the below post:
[https://unix.stackexchange.com/questions/54963/how-can-terminal-emulators-kill-their-children-after-recieving-a-sigkill][1]
The post is bit confusing, still what I got out of the post is that if the process you are killing is the process leader of the process group then all its children will be killed.
So for simplicity, I implemented below program to test if it is so:
int main()
{
printf("Curent PID: %u\n", getpid());
// make a new session
pid_t pid = setsid();
printf("New session ID: %u\n", pid);
pid = fork();
switch(pid)
{
case -1:
perror("UNable to fork the process\n");
exit(EXIT_FAILURE);
case 0:
// child process
while (1)
{
sleep(1);
}
break;
}
while (1)
{
printf("Process Leader running\n");
sleep(1);
}
return 0;
}
After running the above program when I killed the parent process the child process didn't got killed. I also modified the above program so that it does not belong to any tty, I thought might be the process leader should not be associated with any tty. I did that by the following way:
Create a normal process (Parent process)
Create a child process from within the above parent process
The process hierarchy at this stage looks like : TERMINAL -> PARENT PROCESS -> CHILD PROCESS
Terminate the the parent process.
The child process now becomes orphan and is taken over by the init process.
Call setsid() function to run the process in new session and have a new group.
then the same above code repeats.
Still when i killed the process leader children were there.
Maybe I didn't got that post on unix.stackexchange or is it the deafult behaviour in LINUX.
One way that I can implement to make all children kill is by catching each TERMINATING SIGNAL like SIGTERM, SIGHUP etc. handle them and write logic inside those signal handlers to kill child first.But still on SIGKILL I can't do anything.
Also I am interested to know that if killing parent process doesn't affect child process even if the parent is process leader or whatever then how bash(terminal) manages to kill all the child processes even if we send SIGKILL to it. Is there some extra logic written for terminals in LINUX kernel.
If there is a way to kill all child processes when parent is killed even using SIGKILL signal, I would be happy to know that too.
Manual page of kill says:
Negative PID values may be used to choose whole process groups
In my understanding to kill the whole group of processes, you have to send negative PID.
Another mechanism is causing that killing a terminal kills its child processes. Processes running from a terminal have their stdin/stdout attached to the terminal. When killing the terminal, those connections are closed and a signal (SIG_HUP) is sent to those processes. A usual program does not handle this signal and is terminated by default.
The advice from Marian is quite correct and well worth researching, but if you choose to follow that route you will likely end up with an implementation of what might be called the "hostage trick".
The hostage trick consists of your root process spawning an artificial child process which spends all its time in the stopped state. This "hostage" will be spawned immediately before the first child process which does real work in your (multi-process) program.
The hostage process is made the leader of its own process group and then enters a loop in which it stops itself with "raise(SIGSTOP)". If it is ever continued, it checks to see whether its parent has terminated (i.e. whether it has been re-parented or cannot signal its parent with the null signal (ESRCH)). If the parent has terminated, then the hostage should terminate, otherwise it should re-suspend with another "raise(SIGSTOP)".
You need to be careful about race conditions: e.g. for the re-parenting test take care to cache the parent-process-id for the hostage as the return value from "getpid()" before "fork()"-ing the hostage and also make "setpgid()" calls downstream of "fork()" in both parent and child. You then need to consider what you do if someone "kill(., SIGKILL)"s the hostage!
True, you can put a SIGCHLD handler in the parent to re-spawn it, but that requires considerable care to preserve the continuity of the identity of the hostage's process group; maybe there were other child processes at the time of the SIGKILL and the replacement hostage should go in the original process group, maybe there weren't and the original process group has evaporated.
Even if you get that right, the fact that you have put a "fork()" call in a handler for an asynchronous signal (SIGCHLD) will likely open another can of worms if your main process uses multiple threads.
Because of these difficulties I would advise against using the hostage trick unless the child processes run code over which you have no control (and to think seriously about the costs in complexity and maintainability even then). If you have control of the code of the child processes, then it is much simpler to use a "pipe()".
You create the pipe in the parent process and manage the file descriptors to ensure that the parent process is the sole writer and that each child process allocates one file descriptor to the read-side. If you do this, then the termination of the parent process (whether due to SIGKILL or any other cause) is communicated to the child processes by the EoF condition on the read side of the pipe as the last writer terminates.
If you want to treat SIGKILL specially, then you can use a protocol on the pipe whereby the parent process sends a termination message advising the children of its termination status on all normal terminations and on catchable fatal signals, and leaves the children to infer that the parent was killed by SIGKILL in the event that the read-side of the pipe delivers an EoF without a preceding termination message.
On Linux prctl(PR_SET_PDEATHSIG... will arrange for a process to receive a signal when it's parent dies, this setting is preserved over exec but not inherited by child processes.
If I spawn a process in my linux C program and there are 2 processes in total, a parent process and a child process. I want: if one of these 2 processes exits, the other process also exits.
How to achieve this?
are there any similar source codes?
Note: I don't want to block both processes, e.g, I don't want the parent process to be blocked by wait()
thanks!
In father process you can use the waitpid system call. It will block until the child exits.
In the child process you cannot use waitpid. One option would be that the father will inform the child by sending it a SIGTERM on exit. But this will only work if the father won't get killed using SIGKILL. I would suggest to periodically send a signal using kill with param 0 to the father process. If this fails, the process has terminated.
From the kill(2) man page:
if sig is 0, then no signal is sent, but error checking is still performed; this can be used to check for the existence of a process ID or process group ID.
If the child exits, the parent will be sent a SIGCHLD. If the parent is going to die, it should notify the child somehow, or at least send it a SIGTERM.
http://linux.die.net/man/2/waitpid
Wait for any child process, then exit when you return from waitpid.
If the parent process exits, then the child process becomes a zombie process.
If the child exits, the parent can be notified by the wait system call. You can exit the parent by reading the status of it.
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.)
My Linux process has 4 children. After some execution time all children adopted by the init process. How do we prevent this situation? (this is not the case with Zombie processes).
The process is written in C and the OS is Linux. My code calls waitpid! What might be the problem? In 99,99% we don't have this problem.
Last update: What if someone executes "kill -9 "? This terminates immediately the parent process and leaves the children orphan.
If your processes are being reparented by init, that means that their parent process has died. When a process' parent dies, init adopts it so that it can reap the zombie by wait()ing on the child when it (that is, init) receives SIGCHLD.
If you do not want init to become the parent of your children, you will have to ensure that your process lives until all of your children have died and been reaped by your program.
Wait for the children to exit before exiting yourself. See the wait(2) man page for more details.
Check from main page for your waitpid API parameters, and make sure your parent process should not be over before all child processes are finished.
Can you post your code here?
I have a parent and a child process written in C language. Somewhere in the parent process HUP signal is sent to the child. I want my parent process to detect if the child is dead. But when I send SIGHUP, the child process becomes a zombie. How can I detect if the child is a zombie in the parent process? I try the code below, but it doesn't return me the desired result since the child process is still there but it is defunct.
kill(childPID, 0);
One more question; can I kill the zombie child without killing the parent?
Thanks.
from wikipedia:
On Unix and Unix-like computer operating systems, a zombie process or defunct process is a process that has completed execution but still has an entry in the process table. This entry is still needed to allow the process that started the (now zombie) process to read its exit status.
If the parent fetches the exit status by calling wait, waitpid or the like, the zombie should disappear.
You can detect whether a process is alive through the wait functions (man wait).