简体   繁体   中英

Linux signal parent and child [c]

im new to Linux and im still learning my code job is simple it receives a signal from the parent and the child have to ignore the signal and print the number of the signal like [1,3,4,9,11], but my problem is the child does not print anything after the signal plus I want the child to ignore the signals especially like[sigquit] here is my code.

  // 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();
    void sigint();
    void sigquit();
    void sigsegv();
    
    // driver code
    void 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);
      }
    }
    
    // sighup() function definition
    void sighup()
    
    {
      signal(SIGHUP, sighup); /* reset signal */
      printf("CHILD: 1 [sighub]\n");
    }
    
    // sigint() function definition
    void sigint()
    
    {
      signal(SIGINT, sigint); /* reset signal */
      printf("CHILD: 2 [sigint]\n");
    }
    // sigsegv() function definition
    void sigsegv()
    
    {
      signal(SIGSEGV, sigsegv); /* reset signal */
      printf("CHILD: 11 [sigsegv]\n");
    }
    
    // sigquit() function definition
    void sigquit()
    {
    signal(SIGINT, sigquit); /* reset signal */
      printf("3 [sigquit]\n");
      
    }

Check signal.h in /usr/bin/include, signal handler

/* Type of a signal handler.  */
typedef void (*__sighandler_t) (int);

so need to change both the forward declaration and function definition to match this prototype as


 // 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");
      
    }

As mentioned in comments, stdio functions like printf() aren't safe to use in signal handlers. On Linux, you should also use sigaction() instead of signal() to install signal handlers, as that avoids some issues with an imprecise definition of how handlers work in the latter function (Which should only be used when targeting bare bones standard C, not POSIX, where what signal handlers can do is even more restricted than in POSIX).

However, when targeting Linux or Unix platforms, you don't need signal handlers at all for this task! Each process has a signal mask , which controls which signals are blocked from having the normal execution of a handler or default action go off. If a process blocking signal X gets that signal, it's considered pending , and there are other ways to receive it. One such way in Linux is to use a signalfd , a special file descriptor that can be read from to get information about pending signals. An example using it:

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/signalfd.h>
#include <sys/types.h>
#include <sys/wait.h>

int child_main(const sigset_t *, int);
void send_signals(pid_t, int *);

int main(void) {
  // The signals we want to catch
  int signals[] = {SIGHUP, SIGINT, SIGQUIT, SIGSEGV, -1};

  // Set up the signal mask
  sigset_t sigs, oldmask;
  sigemptyset(&sigs);
  for (int i = 0; signals[i] >= 0; i++) {
    sigaddset(&sigs, signals[i]);
  }

  // To avoid a race condition where the parent starts sending signals
  // before the child is ready for them, block the signals before
  // forking the child
  if (sigprocmask(SIG_BLOCK, &sigs, &oldmask) < 0) {
    perror("sigprocmask");
    return EXIT_FAILURE;
  }

  pid_t child = fork();
  if (child < 0) {
    perror("fork");
    return EXIT_FAILURE;
  } else if (child == 0) {
    // In the child process
    return child_main(&sigs, (sizeof signals / sizeof signals[0]) - 1);
  } else {
    // Parent process. Restore the original signal mask and send child signals
    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
      perror("parent sigprocmask");
      kill(child, SIGKILL);
      return EXIT_FAILURE;
    }
    send_signals(child, signals);
    // Wait for the child to finish
    if (waitpid(child, NULL, 0) < 0) {
      perror("parent waitpid");
      return EXIT_FAILURE;
    }
  }

  return 0;
}

void send_signals(pid_t proc, int *signals) {
  for (int i = 0; signals[i] >= 0; i++) {
    printf("Sending process %d signal %s (%d)\n", (int)proc,
           strsignal(signals[i]), signals[i]);
    if (kill(proc, signals[i]) < 0) {
      printf("Failed: %s\n", strerror(errno));
    }
  }
}

int child_main(const sigset_t *sigs, int nsigs) {
  // Create a signalfd that monitors the given signals
  int fd = signalfd(-1, sigs, 0);
  if (fd < 0) {
    perror("child signalfd");
    return EXIT_FAILURE;
  }

  struct signalfd_siginfo s;
  // Loop up to nsigs times reading from the signal fd
  int count = 0;
  while (++count <= nsigs && read(fd, &s, sizeof s) == sizeof s) {
    printf("Child received signal %s (%d)\n", strsignal(s.ssi_signo),
           s.ssi_signo);
  }
  if (count <= nsigs && errno != EINTR) {
    perror("child read");
    close(fd);
    return EXIT_FAILURE;
  }
  close(fd);
  return 0;
}

Example output:

Sending process 17248 signal Hangup (1)
Sending process 17248 signal Interrupt (2)
Sending process 17248 signal Quit (3)
Sending process 17248 signal Segmentation fault (11)
Child received signal Hangup (1)
Child received signal Segmentation fault (11)
Child received signal Interrupt (2)
Child received signal Quit (3)

Your program is running perfectly in my machine, so I don't understand why do you say the child doesn't print anything.

Anyway, you have to be careful, as the child is printing the messages of the received signals, but running forever, this means that when the parent is done and exit() s you leave a child running... forever? (and you are running the child without stopping or blocking, so consuming all the available cpu)

You must devise a method to kill such a process, because if you don't you will end with lots of processes running in your behalf, doing nothing but ignoring the kill() s you do to them.

For that, there are some signals that are not ignorable, the SIGKILL is one, you cannot install a signal handler to it, for security reasons... :)

Also, when using signal(2) system call, the handler is executed on the reception of the first signal, and switches to the default behaviour (which depends on the signal) when the signal handler is done.

If you want it to be permanent, you need to reinstall the signal handler (this has a race condition, in case you receive a second signal while you are executing the signal handler and have not had time to install it again) or call sigaction(2) instead, that allows you to permanently (while the process is running, or up to the next call you do to sigaction ) install a signal handler that doesn't need to be renewed. Look at the manual page of sigaction, as you need to learn how to use it.

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