HackTheGibson
HackTheGibson

Reputation: 73

Unix signals weird behaviour. (children exiting many times)

I am practicing programming with unix signals and I am new to it, so I wrote following program: http://wklej.org/id/2253905/ , that i am compiling in following way: gcc -Wall -o signals signals.c

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <time.h>

void child_work(int l);
void create_children(int n, int l);
void parent_work(int k, int p);
int sethandler( void (*f)(int), int sigNo);
void child_handler(int sig);
void parent_handler(int sig);
void sigchld_handler(int sig);
void usage(void);

volatile sig_atomic_t last_signal = 0;

int sethandler( void (*f)(int), int sigNo)
{
    struct sigaction act;
    memset(&act, 0, sizeof(struct sigaction));
    act.sa_handler = f;
    if (-1==sigaction(sigNo, &act, NULL))
        return -1;

    return 0;
}



void sigchld_handler(int sig) {
    pid_t pid;
    for(;;)
    {
        pid=waitpid(0, NULL, WNOHANG);
        if(pid==0) return;
        if(pid<=0)
        {
            if(errno==ECHILD)
            {
                printf("[%d] No more children parent quits.",getpid());
                exit(EXIT_SUCCESS);
            }

            perror("waitpid:");
            exit(EXIT_FAILURE);
        }
    }
}

void child_handler(int sig)
{
    printf("[%d] received signal %d\n", getpid(), sig);
    last_signal = sig;
    if(last_signal==SIGUSR1)
        if(0==kill(0,SIGUSR2))
            printf("[%d] SENDING signal %d\n", getpid(), SIGUSR2);
        else
            perror("kill:");

}

void parent_handler(int sig) {
    printf("[%d] received signal %d\n", getpid(), sig);
    last_signal = sig;
}

void child_work(int t)
{
    int s;
    srand(getpid());
    s=rand()%(t-1)+2;
    struct timespec tt, tn = {s,0};
    for(tt=tn;nanosleep(&tt,&tt);)
    if(EINTR!=errno)
        perror("nanosleep:");



    printf("[%d] dies",getpid());
    exit(EXIT_SUCCESS);
}


void create_children(int n, int t)
{
    while (n-->0)
    {
        switch (fork())
        {
        case 0:
            if(sethandler(child_handler,SIGUSR1))
            {
                perror("Seting child SIGUSR1:");
                exit(EXIT_FAILURE);
            }

            if(sethandler(child_handler,SIGUSR2))
            {
                perror("Seting child SIGUSR2:");
                exit(EXIT_FAILURE);
            }

            child_work(t);
            exit(EXIT_SUCCESS);

        case -1:
            perror("Fork:");
            exit(EXIT_FAILURE);


        }
    }
}

void usage(void){
    fprintf(stderr,"USAGE: signals n t\n");
    fprintf(stderr,"n - number of children > 0\n");
    fprintf(stderr,"t - max lifetime of child process\n");
}

int main(int argc, char** argv)
{
    int n,t;
    //int childcount;
    if(argc!=3)
    {
        usage();
        return EXIT_FAILURE;
    }

    n = atoi(argv[1]);
    t = atoi(argv[2]);

    if (n<=0 || t<=1) {
        usage();
        return EXIT_FAILURE;
    }

    if(sethandler(SIG_IGN,SIGUSR1))
    {
        perror("Seting parent SIGUSR1:");
        exit(EXIT_FAILURE);
    }

    if(sethandler(parent_handler,SIGUSR2))
    {
        perror("Seting parent SIGUSR2:");
        exit(EXIT_FAILURE);
    }

    if(sethandler(sigchld_handler,SIGCHLD))
    {
        perror("Seting parent SIGCHLD:");
        exit(EXIT_FAILURE);
    }

    create_children(n, t);
    struct timespec tt, tn = {1,0};

    while(1)
    {
        for(tt=tn;nanosleep(&tt,&tt);)
        if(EINTR!=errno) perror("nanosleep:");
        if(0==kill(0,SIGUSR1))
            printf("[%d] SENDING signal %d\n", getpid(), SIGUSR1);
        else
            perror("kill:");

    }




    return EXIT_SUCCESS;
}

and when i run it ./program 3 3 (it spawns 3 children) i get weird output like:

[2835] dies[2836] dies[2834] dies[2836] dies[2836] received signal 10
[2836] received signal 12
[2836] SENDING signal 12
[2835] dies

as you can see [2835] and [2836] die 2 times and I am just wondering why it behaves like this? Thank you in advance for your help.

Upvotes: 2

Views: 51

Answers (1)

jdarthenay
jdarthenay

Reputation: 3147

Using printf() in signal handler function leads to undefined behavior. I was not able to reproduce your bug with my Debian 8.3 Virtual Machine. Behavior will depend on operating system.

Check here Async-signal-safe functions

Upvotes: 1

Related Questions