Lucas
Lucas

Reputation: 169

Why my signal handler executes twice?

I am learning inter-process communication in Linux, using kill() to send signals to sleeping child process.Here is my program:

 8 void func(void);
 9 int main(void){
 10         int i, j;
 11         pid_t status, retpid;
 12         signal(17,func);
 13         if( i = fork() ){
 14                 printf("Parent:signal 17 will be sent to child!\n");
 15                 kill(i, 17);
 16                 wait(0);
 17                 printf("child process terminated\n");
 18                 }
 19         else{   
 20                 sleep(10);
 21                 printf("Child: A signal from my parent is received!\n");
 22                 exit(0);
 23         }
 24 }
 25 void func(void) 
 26 {
 27         printf("the signal has been sent!\n");
 28 }

Compiled with gcc,the program produced abnormal result,in which func() executed twice:

./test4.out
Parent:signal 17 will be sent to child!
the signal has been sent!
Child: A signal from my parent is received!
the signal has been sent!
child process terminated

I analyzed the result and then deleted the following two line:

 16                 wait(0);
 17                 printf("child process terminated\n");

And the result became normal,with func() called only once. It seems that the culprit is wait() function,but why would it ever call a signal handler?

Upvotes: 1

Views: 1936

Answers (2)

user3629249
user3629249

Reputation: 16540

after correcting (most) of the errors in the posted code..

The result is the following code:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

void func( int );

int main(void)
{
    pid_t i;
    //pid_t status;
    //pid_t retpid;
    signal(17,func);


    if( (i = fork()) )
    {
        printf( "the fork'd child pid:%d\n", i );
        printf("Parent:signal 17 will be sent to child!\n");
        kill(i, 17);
        wait(NULL);
        printf("child process terminated\n");
    }

    else
    {   
        sleep(10);
        printf("Child: pid:%d\n", getpid());
        exit(0);
    }
}

void func( int theSignal) 
{
    if( 17 == theSignal )
    {
        fprintf( stdout, "the 17 signal has been processed by %d!\n", getpid());
    }

    else
    {
        fprintf( stdout, "the %d signal is processed\n", theSignal );
    }
}

and the output is:

the fork'd child pid:4845
Parent:signal 17 will be sent to child!
the 17 signal has been processed by 4845!
Child: pid:4845
the 17 signal has been processed by 4844!
child process terminated

Which clearly shows that both the parent and the child process the signal

EDIT:

However when a unique SIGUSR2 value is used as in the following code:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

void func( int );

#define MY_SIGNAL (31)

int main(void)
{
    pid_t i;
    //pid_t status;
    //pid_t retpid;
    signal(17,func);
    signal(31,func);

    if( (i = fork()) )
    {
        printf( "the fork'd child pid:%d\n", i );
        printf("Parent:signal %d will be sent to child!\n", MY_SIGNAL);
        kill(i, MY_SIGNAL);
        wait(NULL);
        printf("child process terminated\n");
    }

    else
    {   
        sleep(10);
        printf("Child: pid:%d\n", getpid());
        exit(0);
    }
}

void func( int theSignal) 
{
    if( MY_SIGNAL == theSignal )
    {
        printf("the %d signal has been processed by %d!\n", MY_SIGNAL, getpid());
    }

    else
    {
        printf( "the %d signal is processed\n", theSignal );
    }
}

then the output is:

the fork'd child pid:5099
Parent:signal 31 will be sent to child!
the 31 signal has been processed by 5099!
Child: pid:5099
the 17 signal is processed
child process terminated

which clearly shows the child processed signal 31 (SIGUSR2) and the parent processed signal 17 (SIGCHLD)

Upvotes: 0

John Kugelman
John Kugelman

Reputation: 361730

You're sending signal 17 to the child process, so its handler is invoked as expected.

Signal 17 is SIGCHLD. SIGCHLD is sent to a parent process when a child process dies. The parent's handler is being called when the child exits. This signal isn't coming from the parent; it's coming from the OS, to notify the parent of the child's death.

Upvotes: 2

Related Questions