Martin Orem
Martin Orem

Reputation: 31

SIGINT ignored by multiple processes

I would like to create three processes, which would print some stuff till I press ctrl+c. Below you can see my try but when a try to stop the program nothing happens. When the only one child is forked, it works good. Where could be a problem? Thanks in advance.

     void my_handler(int s){
          printf("Caught signal %d, I am dying\n",s);
       exit(1);
     }

     void doChild(int count){
     fprintf(stdout,"Child %d with pid: %d\n",count, getpid());
    }


     int main(int argc, char **argv){

     int count = 0;
     pid_t pid;
     struct sigaction sigIntHandler;
     sigIntHandler.sa_handler = my_handler;
     sigemptyset(&sigIntHandler.sa_mask);
     sigIntHandler.sa_flags = 0;
     sigaction(SIGINT, &sigIntHandler, NULL);
     fprintf(stdout, "Ahoj svjete!\n");

     for(;count < 3;count++){
            pid = fork();
    switch(pid){
             case -1:
                    perror("Fork :(");
                     exit(EXIT_FAILURE);

             case 0:
                     while(1){
                            doChild(count);
                    }
       }
    }

     exit(EXIT_SUCCESS);
    }

Upvotes: 1

Views: 437

Answers (2)

Chris Dodd
Chris Dodd

Reputation: 126518

As REACHUS notes, you get 8 processes, not 3. Moreover, the switch tests the result of the last fork calll in each process, so 4 of the processes immediately exit, while the other 4 remain running in the doChild loop.

Now because the top-level process (the initial process that did the first fork) is one of those that exits (its fork calls all return the pids of children, never 0), the shell takes over again, which means that when you hit ctrl-C, it goes to the shell and not to your forked children. Those children never see a SIGINT (unless you send it to them explicitly with kill), so never exit.

Upvotes: 2

syntagma
syntagma

Reputation: 24344

In this loop:

for(;count < 3;count++){
    pid = fork();
}

you will create a total of 8 processes, as you are executing fork() 3 times, i.e. 1. call to fork() gives you 1*2=2 processes, 2nd call to fork() gives you 2*2=4 processes and 3rd call to fork() gives you 4*2=8 processes.

Moreover, the way you setup your signal handler you will be sending your signal to the entire process group (e.g. parent and children). If this is not what you want, you should look at setpgid() and setsid() functions to make the signal work separately for every child process.

EDIT:

Here is a modified version of your code with some additions from me that will help you understand what is going on. You can also find some more explanation as to what is happeninng in your code in Chris Dodds's answer. Sending a signal will now kill all the children and parent process but this code is just an example for you to learn how it works (as I said, you should probably use process groups here).

void my_handler(int s){
    printf("Caught signal %d, I am dying, my PID=%d\n",s, (int)getpid());
    exit(1);
}

void doChild(int count){
    fprintf(stdout,"Child %d with pid: %d\n",count, getpid());
}

int main(int argc, char **argv){
    int count = 0;
    int status;
    pid_t pid;

    for(;count < 2;count++){
        pid = fork();
    }

    printf("My PID=%d\n", (int)getpid());
    fprintf(stdout, "Ahoj svjete!\n");

    switch(pid){
        case -1:
            perror("Fork :(");
            exit(EXIT_FAILURE);
        case 0:
            signal(SIGINT, my_handler);
            while(1){
                doChild(count);
            }
        default:
            printf("Parent\n");
            sigignore(SIGINT);
            wait(&status);
    }

    printf("Process %d ended life.\n", (int)getpid());
    exit(EXIT_SUCCESS);
}

Upvotes: 1

Related Questions