LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 03-16-2011, 10:31 AM   #1
jmarcet
LQ Newbie
 
Registered: Mar 2011
Distribution: Gentoo
Posts: 13

Rep: Reputation: 0
Question Why does a child exit when the parent receives a signal?


Hi,
I have a problem with the last point of some homework I have for an OS class.

I need the program to print the pid upon execution, then for 10 seconds react
to SIGUSR1, SIGUSR2 and SIGTERM. If either USR1 or USR2 is received, the 10 seconds are reset.

Some of the functions I'm told to use are alarm(), pause() and signal().

The nicest way I found was to handle SIGUSR1, SIGUSR2 and SIGALRM in the parent process, with SIGALRM killing the child (with a SIGTERM). In the child a pause() (or for(; pause() would be enough for it to be alive until killed from the SIGALRM handler in the parent.

What I found is that I can't just do a wait() in the parent process, waiting for the child to be killed, since whenever the parent receives a SIGUSR1 or SIGUSR2, the right handler is called but the child exits nicely.

I tried blocking/ignoring those signals in the child, since the default behaviour for SIGUSR1 and SIGUSR2 is to terminate the process, but the result is the same.

The only way I could do it is using a waitpid() within a do { } while(!WIFSIGNALED(status)) since when the child gets killed with the
parent's kill(), it's WIFSIGNALED, whereas when it exits after the parent handles a SIGUSR1/2, it's WIFEXITED.

Is this the expected behavior? Is there any 'standard/recommended' way?

Any help appreciated

P.S. What I'm doing to achieve the expected 10s window is calling alarm(10) in the parent process and again within the SIGUSR1/2 handlers. In the SIGALRM handler I kill the child and within the child I simply do a for(; pause()
 
Old 03-16-2011, 12:01 PM   #2
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
I don't quite understand what you are attempting to achieve (i.e. your requirements are vague).

If you setup the appropriate signal handlers in your main process, then fork a child process, the signals sent to the main process should not affect the child process.

Be aware that waitpid() will return with a status of -1 when a signal is delivered to the main process; you should verify that the errno reason is EINTR, and if so, merely return back to monitoring the child process to determine when it exits. You can also reset your alarm() if/when this condition occurs -- if that is what you want.

You should avoid the use of signal(); it pretty much has been deprecated. Use sigaction() instead; something like:
Code:
struct sigaction act;

memset(&act, 0, sizeof(act));

act.sa_handler = signal_handler;

sigaction(SIGUSR1, &act);
You can reuse the "act" variable if you require multiple signal handlers to be setup.
 
Old 03-16-2011, 02:14 PM   #3
jmarcet
LQ Newbie
 
Registered: Mar 2011
Distribution: Gentoo
Posts: 13

Original Poster
Rep: Reputation: 0
Question

Thanks for your reply.

Let's see. I do indeed use sigaction instead of signal since every updated reference I find says
signal is non portable. But I have to ask whether it is ok to use it. That's not the problem I have, though.

Part of my code is below.

I'll try to paraphrase.

The program has to listen to USR1, USR2 and TERM signals for 10 seconds after being launched.
Whenever USR1 or USR2 is received, the 10s counter is reset again to 10s, that is, there has
to be a 10s space with no signals received.

Those signals increment/decrement some offset for other computation the program later has to do.

The code shows pretty well what I got to, including some debugging code which helped me find the
reason whenever a USR1/USR2 signal was handled, instead of reseting the 10s timer, it exited.

I had to wrap the waitpid within an if which checks its exit status. That way, waitpid returns on
each USR1/USR2 signal received, but, unless the child is killed from the ALRM handler, waitpid
is called again.

In essence, yes, it seems the child never dies, it's the waitpid call which returns on every signal
received. Maybe this is normal, expected behavior. That's what I was asking.

Code:
sig_atomic_t offset = 13;
pid_t child_pid;

void handler (int signal_number)
{
    switch (signal_number) {
        case SIGUSR1:
            offset--;
            alarm(10);
            break;
        case SIGUSR2:
            offset++;
            alarm(10);
            break;
        case SIGALRM:
            kill(child_pid, SIGTERM);
            break;
    }
}

int main (int argc, char *argv[])
{
    char s[100];
    int status;

    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = &handler;
    sigaction( SIGUSR1, &sa, NULL);
    sigaction( SIGUSR2, &sa, NULL);
    sigaction( SIGALRM, &sa, NULL);

    sprintf (s, "My pid is: %ld\n", (long) getpid());
    write (2, s, strlen (s));

    if ( (child_pid=fork()) == -1) {
        error("forking child");
    }
    else if (child_pid == 0) {
        for(;;)
            pause();
    } else {
        alarm(10);
        do {
            waitpid(child_pid, &status, 0);
            if (WIFEXITED(status)) {
                printf("exited, status=%d\n", WEXITSTATUS(status));
            } else if (WIFSIGNALED(status)) {
                printf("killed by signal %d\n", WTERMSIG(status));
            } else if (WIFSTOPPED(status)) {
                printf("stopped by signal %d\n", WSTOPSIG(status));
            } else if (WIFCONTINUED(status)) {
                printf("continued\n");
            }
        } while (!WIFSIGNALED(status));

    ...

    exit (0);
}
 
Old 03-16-2011, 02:36 PM   #4
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: FreeBSD,Debian wheezy
Posts: 811

Rep: Reputation: 179Reputation: 179
Quote:
Originally Posted by jmarcet View Post
In essence, yes, it seems the child never dies, it's the waitpid call which returns on every signal
received. Maybe this is normal, expected behavior. That's what I was asking.
-------->8-------->8-------->8-------->8-------->8-------->8----------
Quote:
Originally Posted by jmarcet View Post
Code:
        do {
            waitpid(child_pid, &status, 0);
            if (WIFEXITED(status)) {
                printf("exited, status=%d\n", WEXITSTATUS(status));
            } else if (WIFSIGNALED(status)) {
                printf("killed by signal %d\n", WTERMSIG(status));
            } else if (WIFSTOPPED(status)) {
                printf("stopped by signal %d\n", WSTOPSIG(status));
            } else if (WIFCONTINUED(status)) {
                printf("continued\n");
            }
        } while (!WIFSIGNALED(status));
Ouch. There's your problem.
  1. When using any library call, read the man page. In this case, use the following shell command:
    Code:
    man waitpid
    If you do not have man pages on your system, go here. Then type waitpid into the box at the top and click the search button. It will give you a choice of a man page from section 2, or a man page from section 3. In this case, it doesn't matter. With experience, you'll get to know which to choose if you have a choice.
  2. When reading the man page, be sure to see what the function returns, if anything. Search the page for RETURN VALUE, and read that section carefully. In this case, as in many others, the function returns -1 as its value in case of error. If so, as the man page states for waitpid(), you need to check the value of the integer errno. To make that possible, you'll need to
    Code:
    #include <errno.h>
    in your code. If the value of the integer is EINTR, you'll need to do the waitpid() over again, because (as you've discovered) a signal will interrupt a waitpid() call. Thus says the man page. The man page speaks truly.
 
Old 03-16-2011, 06:45 PM   #5
jmarcet
LQ Newbie
 
Registered: Mar 2011
Distribution: Gentoo
Posts: 13

Original Poster
Rep: Reputation: 0
Cool

Thanks for the info.

I had read the man pages (I've been a Gentoo user for years).

I was using wait() in my original code. It was after reading a couple books
on the matter (ALP and the recent, wonderful The Linux Programming Interface)
that I replaced it with waitpid() to read the return status and debug my problem.

I sure did not read wait's man page carefully.
The errno variable was the key. Now I do:

Code:
do {
    ret=wait(NULL);
} while (ret==-1 && errno == EINTR);
which not only works fine, it looks good to my eyes.

Thanks again for your help
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Sending Signal from Child Process to Parent Process : Not getting desired output thelink123 Linux - General 4 10-26-2012 09:05 PM
Error : CHILD : exit on signal (11) in free radius AZIMBD03 Red Hat 0 02-18-2006 02:44 AM
Parent child processes signal sharing iftiuk Programming 8 06-24-2004 01:32 PM
[notice] child pid 1296 exit signal Segmentation fault (11) Bigtimelost Linux - General 2 04-13-2004 12:38 PM
Apache: child pid XXX exit signal Segmentation fault (11) gabriele_101 Linux - Hardware 1 07-23-2003 06:12 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 10:14 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration