我现在遇到的问题是,我创建了两个不同的程序(一个将管理另一个,而另一个将被执行多次)。这些程序将通过信号来回通信。我的问题是,是否有可能(以及如何)获取发送信号的程序的进程ID。
我的程序使用signal()来捕获信号,使用kill()来发送信号。
虽然signal()是标准C库中的函数,但它不具备可移植性,其行为取决于系统。最好使用符合POSIX.1标准的sigaction()。
以下是如何使用带有处理程序void h(int sig)的sigaction的示例:
int mysignal (int sig, void (*h)(int), int options)
{
int r;
struct sigaction s;
s.sa_handler = h;
sigemptyset (&s.sa_mask);
s.sa_flags = options;
r = sigaction (sig, &s, NULL);
if (r < 0) perror (__func__);
return r;
}
选项在man sigaction中有描述。一个好的选择是options=SA_RESTART
。
要知道发送信号的进程的PID,设置options=SA_SIGINFO
,并使用sa_sigaction
回调而不是sa_handler
;它将接收一个siginfo_t
结构体,其中包含一个si_pid
字段。您可以使用sigqueue
将数据关联到信号。
一般而言,在安全通信方面使用信号是不好的想法(当发送n个信号时,只有第一个信号有机会被传递;没有钩子来关联其他数据;可用的用户信号仅有两个)。最好使用管道、命名管道或套接字。
// example of a handler which checks the signalling pid
void handler(int sig, siginfo_t* info, void* vp) {
if (info->si_pid != getpid()) {
// not from me (or my call to alarm)
return;
}
// from me. let me know alarm when off
alarmWentOff = 1;
}
这是我设置处理程序的通用代码:
typedef void InfoHandler(int, siginfo_t *, void *);
InfoHandler*
SignalWithInfo(int signum, InfoHandler* handler)
{
struct sigaction action, old_action;
memset(&action, 0, sizeof(struct sigaction));
action.sa_sigaction = handler;
sigemptyset(&action.sa_mask); /* block sigs of type being handled */
action.sa_flags = SA_RESTART|SA_SIGINFO; /* restart syscalls if possible */
if (sigaction(signum, &action, &old_action) < 0)
perror("Signal error");
return (old_action.sa_sigaction);
}
最后,针对这个特定案例:
SignalWithInfo(SIGALRM, handler);
现在已经改变了。信号信息显示的不是1个pid,而是一个简单的数字。这符合killall进程的要求。也许,当你找到/proc/DIGIT时,可以枚举/proc/目录,打开/proc/DIGIT/comm文件,读取并关闭它。也许,获取到的名称将是"shutdown"或"reboot"。
sigaction()
的示例以及信号处理方面的一些复习,可以看看我之前写的这篇文章。 - user405725