简体   繁体   English

Linux信号父子[c]

[英]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.我是 Linux 新手,我仍在学习我的代码工作很简单,它接收来自父母的信号,孩子必须忽略该信号并打印信号的编号,例如 [1,3,4,9,11],但是我的问题是孩子在信号之后不打印任何东西加上我希望孩子忽略信号,特别是像 [sigquit] 这里是我的代码。

  // 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检查 /usr/bin/include 中的 signal.h,信号处理程序

/* 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.正如评论中提到的,像printf()这样的 stdio 函数在信号处理程序中使用是不安全的。 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).在 Linux 上,您还应该使用sigaction()而不是signal()来安装信号处理程序,因为这避免了处理程序如何在后一个函数中工作的不精确定义的一些问题(仅应在针对裸机标准 C 时使用,不是 POSIX,信号处理程序可以做什么比在 POSIX 中更受限制)。

However, when targeting Linux or Unix platforms, you don't need signal handlers at all for this task!但是,当针对 Linux 或 Unix 平台时,您根本不需要信号处理程序来完成这项任务! 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.如果进程阻塞信号 X 收到该信号,则认为它是挂起的,并且还有其他方法可以接收它。 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. Linux 中的一种方法是使用signalfd ,这是一种特殊的文件描述符,可以从中读取以获取有关挂起信号的信息。 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?无论如何,你必须小心,因为孩子正在打印接收到的信号的消息,但是永远运行,这意味着当父母完成并exit() s 你让孩子运行......永远? (and you are running the child without stopping or blocking, so consuming all the available cpu) (并且您在不停止或阻塞的情况下运行孩子,因此消耗了所有可用的 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.你必须设计一种方法来终止这样的进程,因为如果你不这样做,你将以代表你运行的许多进程结束,除了忽略你对它们所做的kill()什么都不做。

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... :)为此,有一些信号是不可忽略的, SIGKILL就是其中之一,出于安全原因,您不能为其安装信号处理程序...... :)

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.此外,当使用signal(2)系统调用时,处理程序在接收到第一个信号时执行,并在信号处理程序完成时切换到默认行为(取决于信号)。

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.如果你希望它是永久性的,你需要重新安装信号处理程序(这有一个竞争条件,以防你在执行信号处理程序时收到第二个信号并且没有时间再次安装它)或调用sigaction(2)相反,它允许您永久(在进程运行时,或直到您对sigaction执行的下一次调用)安装不需要更新的信号处理程序。 Look at the manual page of sigaction, as you need to learn how to use it.查看 sigaction 的手册页,因为您需要学习如何使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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