tags:

views:

1068

answers:

4

In my program, I fork() several times depending on user input.

In certain instances, I want to handle SIGCHLD and say something like "Process # Finished". In other cases though, I want to ignore this signal.

How can I do this?

+2  A: 

Signal handling is set up globally for the process. If you want to catch an asynchronous signal like SIGCHLD when some children terminate but not others, you can't decide to ignore it for some in advance.

You will need to handle the signal every time in the parent, then decide whether you want to ignore it in your handler.

At minimum, your handler should do a wait() on the child (si_pid in the siginfo_t structure) to harvest its return code. At that point you can check the process id and decide what else to do. You don't have to print anything if you don't want to.

Carlos A. Ibarra
A: 

If you ignore SIGCHLD then the process table will fill up with zombies.

Graham Lee
In some flavors of unix, ignoring SIGCHLD automatically reaps the child processes (apparently). http://www.faqs.org/faqs/unix-faq/faq/part3/section-13.html
Greg Rogers
+1  A: 

You can use waitpid function in either blocking or non-blocking mode to wait for the signal from a given child and then do some processing. In fact, you have to use wait of some sort, as it is stated in Graham's answer...

stanch
+1  A: 

You want to catch the signal SIGCHLD and then call a function. You want to use signal() to do this (man signal). In the below example child_died() is called after the signal SIGCHLD is caught (child process is dead at this point). If there is info that you need to pass from the child to the parent that child_died() needs for a conditional, you'll need to use a pipe (man pipe). Here is an example of signal and pipe:

#include <signal.h>
#include <strings.h>
#include <stdio.h>

#define MAX_SIZE 256

void child_died(int);

int fd[2];

int main()
{
    int pid;
    extern int fd[];
    char *str;

    pipe(fd);
    signal(SIGCHLD, child_died);

    if ((pid = fork()) < 0) {
        // error
        printf("Error\n");
    } else if (pid == 0) {
        // child
        printf("In child process\n");
        close(fd[0]);
        str = strdup("Message from child process.\n");
        write(fd[1], str, strlen(str) + 1);
    } else {
        // parent
        wait();
        printf("Now in parent\n");
    }

    return 0;
}

void child_died(int s)
{
    char *str;
    close(fd[1]);
    read(fd[0], str, MAX_SIZE);
    printf("%s", str);
}

Saved as sigchld.c and compiled with: gcc -Wall sigchld.c -o sigchld

If you want to pass an int (like the child pid) or some other data type from the child process to the parent process you'll either will have to convert it to a string and back again or find another way to do it.

If you want to ignore SIGCHLD then in my example you would put that logic into child_died(). Just use a simple if. I don't know how you are deciding when to ignore the signal and when to print what you want, that's why I included the pipe stuff in my code above. I figured you would use some info from the child process and since child_died() is called on the parent process, you will need a way to transfer data from the child to parent process.

I hope this helps. There may be better or easier ways of accomplishing this that I don't know of. If there are then please comment.

Mark Testa