【发布时间】:2012-07-15 13:03:06
【问题描述】:
假设我的 C 程序处理 SIGUSR1。
当它收到这个信号时,有没有可能知道是谁发出的? 即,如何获取发送者进程的pid?
【问题讨论】:
标签: c linux signals system ipc
假设我的 C 程序处理 SIGUSR1。
当它收到这个信号时,有没有可能知道是谁发出的? 即,如何获取发送者进程的pid?
【问题讨论】:
标签: c linux signals system ipc
是的,如果您使用sigaction() 调用而不是signal 来设置您的信号处理程序。这样做可以让您设置一个接受三个参数的信号处理程序:
int,用于信号编号(就像signal)siginfo_t *,这是一个包含有关信号源的各种信息的结构,包括发送者的 pid(如果适用)。 (它还包括一些关于自动信号的信号原因的信息,例如SIGSEGV。)ucontext_t *,与哪个线程收到信号有关。几乎可以忽略不计。【讨论】:
是的。使用带有SA_SIGINFO 标志的sigaction 注册您的信号处理程序,并填写sa_sigaction 字段。现在你的处理函数接受一个siginfo_t* 参数,其中包括一个字段si_pid。
请注意,si_pid 仅在某些情况下设置。在您的情况下,您需要检查 si_code 是否设置为 SI_USER 或 SI_QUEUE。阅读man 2 sigaction了解更多信息。
【讨论】:
另一个选项是使用signalfd()。如果您使用信号在进程之间发送信息,那么比信号处理程序更结构化的信号处理很可能是您想要的。 struct signalfd_siginfo::ssi_pid 是发件人。
手册页示例:
#include <sys/signalfd.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int main(int argc, char *argv[]) {
sigset_t mask;
int sfd;
struct signalfd_siginfo fdsi;
ssize_t s;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGQUIT);
/* Block signals so that they aren't handled
according to their default dispositions */
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
handle_error("sigprocmask");
sfd = signalfd(-1, &mask, 0);
if (sfd == -1)
handle_error("signalfd");
for (;;) {
s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
if (s != sizeof(struct signalfd_siginfo))
handle_error("read");
if (fdsi.ssi_signo == SIGINT) {
printf("Got SIGINT\n");
} else if (fdsi.ssi_signo == SIGQUIT) {
printf("Got SIGQUIT\n");
exit(EXIT_SUCCESS);
} else {
printf("Read unexpected signal\n");
}
}
}
另请参阅: sigqueue()。与kill() 类似,但您可以在同一个调用中传递整数或指针。
【讨论】:
这是 POSIX 标准 sigaction() API 的完整示例:
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void sigusr1(int signo, siginfo_t *si, void *data) {
(void)signo;
(void)data;
printf("Signal %d from pid %lu\n", (int)si->si_signo,
(unsigned long)si->si_pid);
exit(0);
}
int main(void) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = sigusr1;
if (sigaction(SIGUSR1, &sa, 0) == -1) {
fprintf(stderr, "%s: %s\n", "sigaction", strerror(errno));
}
printf("Pid %lu waiting for SIGUSR1\n", (unsigned long)getpid());
for (;;) {
sleep(10);
}
return 0;
}
尝试运行它,然后发送 SIGUSR1(例如,来自 shell 的 kill -SIGUSR1 that-pid)
sigaction函数:http://pubs.opengroup.org/onlinepubs/009604499/functions/sigaction.html
siginfo 结构:http://pubs.opengroup.org/onlinepubs/009604499/basedefs/signal.h.html
【讨论】: