Link to home
Start Free TrialLog in
Avatar of avidamani
avidamani

asked on

signal handler for SIGCHLD gets called twice if parent process also gets killed

Hi,

I have a parent process that forks a child process and from there execlp another executable. The parent process and the exe uses pipes for IPC. The parent process has a signal handler that handles the SIGCHLD signal as follows :

    struct sigaction act;

    act.sa_handler = SIG_IGN;
    sigemptyset(&act.sa_mask);
    act.sa_flags   = 0;
    sigaction(SIGPIPE, &act, 0);

    act.sa_handler = child_killed; //handler function
    act.sa_flags  = SA_NOCLDSTOP | SA_NODEFER;
    sigemptyset(&act.sa_mask);

    if(sigaction(SIGCHLD,&act,0)) {
        exit(1);
    }

In the child_killed(), I close the read end of the pipe.
Some times just after the child process exits, the parent process goes 100% (at times I see that the signal handler gets called in logs and some times i do not see the logs, so i cannot be sure that everytime the problem happens the signal handler gets called in parent). Also the child process becomes a Zombie. After I kill and restart the Parent process I see in its logs that the signal handler is called again but this time with child pid as -1.  

Can you please tell me why the signal handler is getting called in the newly started parent process.

Also I would like to know that whether there is a chance that even after the child exits the signal handler doesn't gets called in the parent.

Thanks,
Avinash
Avatar of sunnycoder
sunnycoder
Flag of India image

>Can you please tell me why the signal handler is getting called in the newly started parent process.
cannot be unless there is a bug in the library ... run your program through a debugger

>whether there is a chance that even after the child exits the signal handler doesn't gets called in the parent.
yes, if you are executing child_killed() when a child exits, signal will not be delivered ... this is the default behaviour... when you are handling a signal and same signal arrives, it is not delivered ... also if more than one children exit simultaneously, your application will see only one signal
you might like to look into sigpending()
Avatar of avidamani
avidamani

ASKER

Hi sunnycoder,

Thanks for the reply. Can you elaborate which library are you talking about.

Also there is only one child process, so there is no chance of getting another sigchild. THe problem is that the parent process goes upto 100% CPU utilization around the time the child exits. There is no way to confirm whether the parent went 100% before the sigchld came or after that. Also the problem is happening rarely and so there is no way to reproduce it with the code as it is.
1 more thing, is it possible to miss a signal if theparent process is very busy processing something else.
Cause i know for sure that if i do not close the reading end of the pipe after the child exits, parent process will shoot upto 100% quickly, but whats baffling me is that why the sigchld handler is not getting called.

Thanks,
Avinash

Also to add, The parent and child process are communicating through pipe, where Child is the writer and parent reads from the pipe using the following :

       XtAddInput(fd, (char *)xmask, callback, ptr));

Now if the child exits/gets killed, what will the status of the pipe at parent, will the callback keep on getting called? SIGPIPE signal comes when you write to a pipe which has no reader. right? Is there anything that tells that the pipe is empty from which you are reading, i.e. there is no writer to it.

Thanks,
Avinash
Could you please post a bit more of you code
1) where do you call pipe() and fork()
2) more important, where and how do you call wait() or waitpid(). Since, you are getting zombies, I assume, it is something wrong with waiting.
If the parent doesn't wait, but exits before the child process does, then the child is adopted by another process (usually the one with PID 1). After the child exits (but before it's waited for) it becomes a "zombie". If it's never waited for (because the parent process is hung, for example) it remains a zombie.

I post just a small example for fork() and pipe()
http://www-h.eng.cam.ac.uk/help/tpl/unix/fork.html
1)The fork code :  
   ============
 if ((pid = fork()) < 0)
    {
        if (pipe_ok) {
            close(fd[0]);
            close(fd[1]);
        }
        return;
    }
    else
    {
        if (pid == 0)
        {
            // Close the read half of the pipe.
            if (pipe_ok)
                close(fd[0]);

            // I AM THE CHILD - transform into another process
            if (execlp(a_exec,
                       a_exec,
                       (char *)NULL) < 0)
            {
                 exit(2);
            }
        }



2) I am calling wait() in the signal handler. So the child will remain Zombie till its signal handler is called.
   
     c_pid = wait(&c_status);

    I understand the zombie concept but since I'm calling wait in the signal handler, and signal is the highest
    priority stuff in unix, even though parent is hung/busy, the signal handler should get called.
   
    Also I'm not sure why the signal handler is called again after I've kill/restarted the parent process, even though there was only 1 child that was killed and was in zombie state. Since init will adopt the zombie and clean it up as it is now an orphan.

Thanks
The code for // I AM THE PARENT ?

I guess, you have a big project with GUI and it is difficult to post all you source...
If you want, you can send me the code to fsign21@gmx.net and I can have a look on it.
I cannot post the source code as its a proprierty thing. But yaa its a bif project :)
I was wondering what made the signal handler to get called after the parent process was killed. In this case, the init will take over the child and clean it up as child exited before parent was killed.
sorry for late reply.. I was away on a vacation ... were you able to solve the problem or is it still open?
The problem is still there..... :(
>1 more thing, is it possible to miss a signal if theparent process is very busy processing something else
no

>Cause i know for sure that if i do not close the reading end of the pipe after the child exits
as far as I remember, you should be closing the read end first

>SIGPIPE signal comes when you write to a pipe which has no reader. right?
right

>Is there anything that tells that the pipe is empty from which you are reading, i.e. there is no writer to it.
No signal but reads will return nothing... that is sufficient diagostic that no data is available

>and signal is the highest priority stuff in unix,
some interrupts have higher priority

>why the signal handler is called again after I've kill/restarted the parent process
this is strange and I am surprised too... add some code to signal handler and in that signal handler print the ID of the process which sent the signal... to get this id print the si_pid member of siginfo_t .. also try running the code through a debugger

>init will adopt the zombie and clean it up as it is now an orphan.
no, it wont clean it up
The signal handler is getting called in the next process with pid of -1
is it a daemon process? are you using setsid() or fork to make it process group leader ?
Yes it is... It gets restarted as soon as it gets killed from inittab.
I'll try to explain the scenario again.

1) client makes a call.
2) This process forks off a child.
3) The child exits and becomes a zombie.
4) The parent at times hits the signal handler .. at times dont
5) I kill the parent after some time (once after 1 day)
6) The new process gets respawned from inittab entry
7) Its signal handler gets hit and the child pid is shown as -1 when i do a wait in the signal handler.

I want to know why the signal handler of the new process gets hit. It didn't do a fork() or setsid(). Fork() was done by the previous process which I killed.
2) This process forks off a child.
3) The child exits and becomes a zombie.
4) The parent at times hits the signal handler .. at times dont

I am sure you are missing out on something in your code ... Check it again or still better ask someone else to do it for you .... IPC mechanism is a time-tested mechanism which has stood for decades now ... This is an issue with your code.

>7) Its signal handler gets hit and the child pid is shown as -1 when i do a wait in the signal handler.
how do you get the child pid ? pid of -1 is invalid for a sending process... However, it is possible to send a signal to pid -1. This would send a signal to all the processes in the group except the first one
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

PAQ  No refund

Please leave any comments here within the next seven days.

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

liddler
EE Cleanup Volunteer
ASKER CERTIFIED SOLUTION
Avatar of modulo
modulo

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial