简体   繁体   中英

Linux Signal : Child not receiving

my code is a simple c code where have two processes first one the parents sends signals and print out what it send and the other is the child that receives the signals and print what it received the output of my code is PARENT: sending SIGHUP PARENT: sending SIGINT PARENT: sending SIGQUIT it should be PARENT: sending SIGHUP child received SIGHUP etc...

 // C program to implement sighup(), sigint()
    // and sigquit() signal functions
    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>

    
    // function declaration
    void sighup(int);
    void sigint(int);
    void sigquit(int );
    void sigsegv(int );
    
    // driver code
    int main()
    {
      int pid;
    
      /* get child process */
      if ((pid = fork()) < 0) {
        perror("fork");
        exit(1);
      }
    
      if (pid == 0) { /* child */
        signal(SIGHUP, sighup);
        signal(SIGINT, sigint);
        signal(SIGQUIT, sigquit);
                    signal(SIGSEGV, sigsegv);
        for (;;)
          ; /* loop for ever */
      }
    
      else /* parent */
      { /* pid hold id of child */
        printf("\nPARENT: sending SIGHUP\n\n");
        kill(pid, SIGHUP);
    
        sleep(3); /* pause for 3 secs */
        printf("\nPARENT: sending SIGINT\n\n");
        kill(pid, SIGINT);
    
        sleep(3); /* pause for 3 secs */
        printf("\nPARENT: sending SIGQUIT\n\n");
        kill(pid, SIGQUIT);
        sleep(3);
      }
return  0 ;
    }
    
    // sighup() function definition
    void sighup(int signo)
    
    {
      signal(SIGHUP, sighup); /* reset signal */
      printf("CHILD: 1 [sighub]\n");
    }
    
    // sigint() function definition
    void sigint(int signo)
    
    {
      signal(SIGINT, sigint); /* reset signal */
      printf("CHILD: 2 [sigint]\n");
    }
    // sigsegv() function definition
    void sigsegv(int signo)
    
    {
      signal(SIGSEGV, sigsegv); /* reset signal */
      printf("CHILD: 11 [sigsegv]\n");
    }
    
    // sigquit() function definition
    void sigquit(int signo)
    {
    signal(SIGINT, sigquit); /* reset signal */
      printf("3 [sigquit]\n");
      
    }

Probably the first signal is sent before the child has initialized it's signal handling. At least I could reproduce the behaviour by adding sleep(2); directly after if (pid == 0) { .

Try adding a sleep() in the parent process before you start sending signals

You have several "issues" with the logic of the code (apart from the use of the non async-signal-safe functions).

  1. There is no guarantee which process will start working after the fork() . This depends on the kernel and on the system. Linux kernel allows you to make this a deterministic by setting a value in /proc/sys/kernel/sched_child_runs_first , where if value is 0 (default) the parent runs first, and if value is non-zero the child runs first. Nevertheless, it's not a good practice to depend on this switch for the synchronisation, since on multiprocessor environments, both can run at the same time if we have available CPUs.

  2. The processes can be pre-empted at any given moment, either due to the use of system calls, or due to the cpu time. Therefore, there is no guarantee that the child had set all the signal handlers before the parent had issued the signals, so some of the signals are lost (actually on my tests I got cases where all signals ware lost, once sleep was removed).

  3. For the same reason as 2, there is no guarantee that the child got the signal before parent sends the new signal.

To solve the problem and guarantee the order of execution, you need to create a synchronisation barrier(s). Here is example based on IPC pipes that assures the synchronisation. In the example, the parent waits for the child to set-up the signals, and than, for each signal it sends, it waits for the child to confirm that the signal was received.

// C program to implement sighup(), sigint()
// and sigquit() signal functions
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>


// function declaration
void sighup(int);
void sigint(int);
void sigquit(int );
void sigsegv(int );

int fd[2]; // communication pipe

// driver code
int main()
{
    int pid;

    if (pipe(fd)==-1)
    {
        fprintf(stderr, "Pipe Failed" );
        exit(1);
    }

    /* get child process */
    if ((pid = fork()) < 0) {
        perror("fork");
        exit(1);
    }

    if (pid == 0) { /* child */
        close(fd[0]); // Close reading end
        printf("Preparing the signals");
        signal(SIGHUP, sighup);
        printf(".");
        signal(SIGINT, sigint);
        printf(".");
        signal(SIGQUIT, sigquit);
        printf(".");
        signal(SIGSEGV, sigsegv);
        printf(".Signals ready\n");
        write(fd[1],"ready\0", 6);
        for (;;)
            ; /* loop for ever */
    }

    else /* parent */
    { /* pid hold id of child */
        char readb[1024];
        readb[1023] = 0; //Safty stop

        close(fd[1]); // Close writting end
        printf("Waiting for child to finish\n");
        read(fd[0], readb, 1023);
        printf("Child sends %s", readb);

        printf("\nPARENT: sending SIGHUP\n\n");
        kill(pid, SIGHUP);
        read(fd[0], readb, 1023);
        printf("%s\n", readb);

        printf("\nPARENT: sending SIGINT\n\n");
        kill(pid, SIGINT);
        read(fd[0], readb, 1023);
        printf("%s\n", readb);

        printf("\nPARENT: sending SIGQUIT\n\n");
        kill(pid, SIGQUIT);
        read(fd[0], readb, 1023);
        printf("%s\n", readb);

        close(fd[0]);
    }
    return  0 ;
}

// sighup() function definition
void sighup(int signo)
{
    signal(SIGHUP, sighup); /* reset signal */
    write(fd[1],"CHILD: 1 [sighub]\0",18);
}

// sigint() function definition
void sigint(int signo)

{
    signal(SIGINT, sigint); /* reset signal */
    write(fd[1],"CHILD: 2 [sigint]\0",18);
}
// sigsegv() function definition
void sigsegv(int signo)
{
    signal(SIGSEGV, sigsegv); /* reset signal */
    write(fd[1],"CHILD: 11 [sigsegv]\0",20);
}

// sigquit() function definition
void sigquit(int signo)
{
    signal(SIGINT, sigquit); /* reset signal */
    write(fd[1],"CHILD: 3 [sigquit]\0",19);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM