If an application does a fork() and the child dies with an abort() (due to failing an assert()), will the parent process receive a SIGCHLD?
If it's relevant this is on Debian 4 (gcc version 4.1.2).
If you want to check the same,write a sample code which forks a child and the child calls abort() (To raise the sigabrt signal). Check its output on strace.(strace executable)
For the following code:
#include<stdio.h>
#include<unistd.h>
int main()
{
pid_t pid;
if(pid=fork()<0)
{
fprintf(stderr,"Error in forking");
}
else if(pid==0)
{
/*The child*/
abort();
}
else {
waitpid(pid,(int *)0,0);
}
return 0;
}
I get this output:
--- SIGCHLD (Child exited) # 0 (0) ---
gettid() = 4226
tgkill(4226, 4226, SIGABRT) = 0
--- SIGABRT (Aborted) # 0 (0) ---
+++ killed by SIGABRT +++
So the answer is yes, at least on Ubuntu distro.
You would expect the parent to get a SIGCHLD any time a child terminates unless the child has separated itself off from the parent (IIRC using setsid() or setpgrp()). The main reason for a child doing this is if the child is starting a daemon process. See Here or Here for a deeper treatment of daemon processes.
Related
This is a C language program in Linux (ubuntu). I've been trying to figure out how to get the status of a child process from a parent.
I've written a simple child process that counts to 25 over 25 seconds and outputs a tick count to standard output. In the parent process I 1> stop the child process for a couple of seconds. 2> continue it for a couple of seconds and then 3> kill the child process. I want to get the status of the child process, for which I've been using the waitpid() function. However, I find that if I used the flags:
waitCondition = WUNTRACED | WCONTINUED
it does return the "stopped" status, but it hangs when it's in the continue state.
Conversely, if I set the flags to:
waitCondition= WUNTRACED | WCONTINUED | WNOHANG
The stop status is not registered, but the continue status is registered by waitpid().
I'm trying to get the parent to recognize the state when it has stopped, continued or exited.
I have the code below. Does anyone have any ideas for this? Thanks!
int waiting4pid()(pid_t processID)
{
int waitCondition = WUNTRACED | WCONTINUED;
int currentState;
while (waitpid(processID,¤tState,waitCondition) > 0){
if(WIFCONTINUED(currentState)){
printf("\n currentState = continued!\n");
}
if(WIFSIGNALED(currentState)){
printf("\n currentState = signaled!\n");
}
if(WIFSTOPPED(currentState)){
printf("\n currentState = stopped!\n");
}
}
}
void sigTest()
{
pid_t processID;
processID = fork();
if(processID ==0) { // child
// tmp/loop is an application that counts to 25 in 25 seconds and then exits.
execlp("tmp/loop", "tmp/loop", NULL);
}else{
sleep(2);
printf("\n Stop!");
kill(processID, SIGSTOP);
waiting4pid()(processID);
sleep(2);
printf("\n Continue!");
kill(processID,SIGCONT);
waiting4pid()(processID);
sleep(2);
printf("\n Kill!");
kill(processID, SIGKILL);
waiting4pid()(processID);
}
}
void main()
{
sigTest();
}
In order to check if the process exited, do:
if(WIFEXITED(status) {
// do your stuff
// you can also check the exit status
if(WEXITSTATUS(status) != EXIT_SUCCESS) {
// the child process exited with error
}
}
As already mentioned by #kaylum in a comment under the question, the waitpid() call blocks until the child changes state. But you can modify this behaviour by calling waitpid() with WNOHANG flag set (that would be useful if you need to monitor the child process but at the same time do some other stuff in the parent; alternatively you can waitpid() in a separate thread).
I'm trying to create a zombie process with the kill function but it simply kills the child and returns 0.
int main ()
{
pid_t child_pid;
child_pid = fork ();
if (child_pid > 0) {
kill(getpid(),SIGKILL);
}
else {
exit (0);
}
return 0;
}
When I check the status of the process there is no z in the status column.
Here is a simple recipe which should create a zombie:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
int main()
{
int pid = fork();
if(pid == 0) {
/* child */
while(1) pause();
} else {
/* parent */
sleep(1);
kill(pid, SIGKILL);
printf("pid %d should be a zombie\n", pid);
while(1) pause();
}
}
The key is that the parent -- i.e. this program -- keeps running but does not do a wait() on the dying child.
Zombies are dead children that have not been waited for. If this program waited for its dead child, it would go away and not be a zombie. If this program exited, the zombie child would be inherited by somebody else (probably init), which would probably do the wait, and the child would go away and not be a zombie.
As far as I know, the whole reason for zombies is that the dead child exited with an exit status, which somebody might want. But where Unix stores the exit status is in the empty husk of the dead process, and how you fetch a dead child's exit status is by waiting for it. So Unix is keeping the zombie around just to keep its exit status around just in case the parent wants it but hasn't gotten around to calling wait yet.
So it's actually kind of poetic: Unix's philosophy here is basically that no child's death should go unnoticed.
The code is one of the answers to this question.
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void
sigusr1( int pidno )
{
fprintf(stderr, "Caught\n");
}
int
main()
{
pid_t pid;
signal( SIGINT, sigusr1 );
if( (pid = fork()) == 0 ){
pause();
fprintf(stderr, "Child\n");
}
else
{
fprintf(stderr, "Parent\n");
kill( pid , SIGINT ); //parent sends signal to child
}
pause();
return 0;
}
The child waits for a signal, and after receiving it continues execution.
Running it I get
Parent
Caught
It seems that the child does not runs after receiving the signal. Pressing Ctrl+c:
Parent
Caught
^CCaught
Caught
Child
Can somebody explain me what is happening here?
pause() gets invoked after the signal has been received and handled by the child. Unfortunately, pause() easily introduces this kind of race condition:
time you parent child
---- --- ------ -----
0 signal(SIGINT,handler)
1 fork() (hello)
2 print("Parent") (waking up)
3 kill(..., SIGINT) <<SIGINT>> # RACE kill v pause
4 handler: print("Caught")
5 pause() pause()
6 ^C <<SIGINT>> <<SIGINT>>
7 handler: print("Caught") handler: print("Caught")
8 exit pause()
9 (still running)
To check what exactly goes on, try adding %i, getpid() to printfs, and maybe also one more printf() before the pause() call in the child branch.
sigsuspend() and explicit signal masking might be a better choice here.
I am not able to understand the output for the following program. I observed that after the child process returns, parent process is not sleeping for 3 sec before wait(). If SIGCHLD is set to default handler, then it sleeping for 3 sec, calling wait and returning as expected. What is exactly happening here ??
# include <unistd.h>
# include <sys/types.h>
# include <stdio.h>
# include <sys/wait.h>
# include <signal.h>
void handler(int sig) {
printf("Iam in handler ...\n");
}
main() {
int status;
pid_t pid;
struct sigaction act;
//act.sa_flags=SA_NOCLDSTOP;
act.sa_handler=handler;
sigaction(SIGCHLD,&act,NULL);
if(!fork()) {
printf("child process id is %d\n",getpid());
return 1;
}
printf("xxx ...\n");
sleep(3);
pid = wait(&status);
printf("process terminated is %d\n",pid);
}
output::
xxx ...
child process id is 2445
Iam in handler ...
process terminated is 2445
From the man for sleep():
sleep() makes the calling thread sleep until seconds seconds have elapsed or a signal arrives which is not ignored.
Your child terminating causes a signal to wake you up.
The return value from sleep():
Zero if the requested time has elapsed, or the number of seconds left to sleep, if the call was interrupted by a signal handler.
Can be used if you'd like to help you "finish" the sleep.
unsigned sleep_time = 3;
...
while((sleep_time = sleep(sleep_time)) > 0) {}
pid = wait(&status);
...
When the child process dies a SIGCHLD is sent to the parent. In your case it interrupts the sleep and it looks as if the process doesn't sleep.
The gist of the issue: sleep isn't restarted when interrupted by a signal.
I have a CGI script running on "mongoose webserver" written in C++ (independent of mongoose specific APIs for portability in the future) on Ubuntu 10.04. Whenever I invoke the script from web browser (Chrome), the process works fine but when I run ps -al I see
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 3567 8877 0 80 0 - 23309 hrtime pts/0 00:00:00 mongoose
4 Z 0 3585 3567 7 80 0 - 0 exit pts/0 00:00:00 test <defunct>
I use sudo kill -9 3567 in this case to kill the parent process. I have the following code in my script.
...
#include <sys/wait.h>
...
//==========================================================================
// Define the function to be called when ctrl-c (SIGINT) signal is sent to process
static void signal_callback_handler(int signum)
{
point_of_inspection( __FILE__, __func__, __LINE__, ENABLE_LOG); // Entered the routine
// Cleanup and close up stuff here
while(1)
{
if (signum == SIGTERM)
{
error_log_report("caught signal - premature exit",CAUGHT_SIGNAL_ERROR,ENABLE_LOG);
break;
}
}
clean_exit();
// Terminate program
exit(signum);
}
//======================= Zombies or <defunct> handler ========================
// Signal handler to process terminated children
static void mysig(int nsig)
{
int nStatus, nPid;
while(1)
{
if (nsig == SIGCHLD)
{
nPid = waitpid(-1, &nStatus, WNOHANG);
if(nPid<0)
{
error_log_report("waitpid (nPid<0)",CAUGHT_SIGNAL_ERROR,ENABLE_LOG);
break;
}
if(nPid==0)
{
error_log_report("Caught Signal - Zombies <defunct> (nPid==0)",CAUGHT_SIGNAL_ERROR,ENABLE_LOG);
break;
}
}
}
clean_exit();
exit(nsig);
}
In the main function
int main()
{
//some initialization variables
...
// Register signal and signal handler
signal(SIGTERM, signal_callback_handler);
// To clean up terminated children
signal(SIGCHLD, mysig);
...
return 0;
}
However, It seems to not catch any signal triggered when the user closes web browser or navigates to a different page as I do not see any logs. I am wondering if this is a bug in mongoose or my script (I do not use any fork() process or threads in my script. But mongoose does use threads. Also I do not use any mongoose webserver specific APIs in my script.).
I am referring the signal tutorial from here http://orchard.wccnet.org/~chasselb/linux275/ClassNotes/process/sigbasics.htm and
http://www.gnu.org/s/hello/manual/libc/Process-Completion.html
They updated the code in mongoose.c file to reap zombies. The following is the portion of the code.
#if !defined(_WIN32) && !defined(__SYMBIAN32__)
// Ignore SIGPIPE signal, so if browser cancels the request, it
// won't kill the whole process.
(void) signal(SIGPIPE, SIG_IGN);
// Also ignoring SIGCHLD to let the OS to reap zombies properly.
(void) signal(SIGCHLD, SIG_IGN);
#endif // !_WIN32
zombie processes in Unix are processes which are terminated but not waited yet by the parent process. Their presence should be temporary or is denoting a bug in the parent, in the present case mongoose.