【问题标题】:How, in Perl 5, can I get the pid of the process who sent me a signal?在 Perl 5 中,如何获取向我发送信号的进程的 pid?
【发布时间】:2011-06-09 16:47:23
【问题描述】:

在 C 中,我可以说

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

int continue_running = 1;

void handler(int signal, siginfo_t* info, void* data) {
    printf("got signal %d from process %d running as user %d\n",
        signal, info->si_pid, info->si_uid);
    continue_running = 0;
}


int main(int argc, char** argv) {
    struct sigaction sa;
    sigset_t mask;

    sigemptyset(&mask);

    sa.sa_sigaction = &handler;
    sa.sa_mask      = mask;
    sa.sa_flags     = SA_SIGINFO;

    sigaction(SIGTERM, &sa, NULL);

    printf("pid is %d\n", getpid());

    while (continue_running) { sleep(1); };

    return 0;
}

这会打印出类似的东西

pid is 31980
got signal 15 from process 31985 running as user 1000

当从进程 31985 发送SIGTERM 时。

我可以使用POSIX::sigaction 编写类似的 Perl 5 代码:

#!/usr/bin/perl

use strict;
use warnings;

use POSIX;
use Data::Dumper;

my $sigset = POSIX::SigSet->new;

$sigset->emptyset;

my $sa = POSIX::SigAction->new(
    sub { print "caught signal\n" . Dumper \@_; $a = 0 },
    $sigset,
);

$sa->flags(POSIX::SA_SIGINFO);

$sa->safe(1); #defer the signal until we are in a safe place in the intrepeter

POSIX::sigaction(POSIX::SIGTERM, $sa);

print "$$\n";

$a = 1;
sleep 1 while $a;

但处理程序仍然只接收一个参数(信号)。我怎样才能获得siginfo_t 结构?是否必须编写我自己的 XS 代码来设置自己的处理程序,然后将信息传递给 Perl 回调?在 XS 中编写我自己的处理程序会以某种方式搞砸解释器吗?

【问题讨论】:

  • 我希望我能多次对此表示赞同。这是一个非常棒的问题。您是否查看过 POSIX 模块中现有的 XS 代码?我没有,但我敢打赌这就是你问题的答案所在。至于搞砸解释器,你知道解释器循环的“安全信号”变化吗?
  • @tchrist 是的,我知道在 5.8 行的某个时间点发生的变化。这就是我所担心的。我不知道如何与这些东西的工作方式交互。阅读 POSIX XS 的东西可能是要走的路。我希望有人已经为我完成了艰苦的工作。
  • 如果@tchrist 喜欢它,那对我来说已经足够了:+1

标签: perl signals


【解决方案1】:

sighandler(在mg.c 中找到)是围绕 Perl 信号处理程序子的包装器。如您所见,它能够将您想要的信息发送到 Perl 信号处理程序子。

#if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
    {
        struct sigaction oact;

        if (sigaction(sig, 0, &oact) == 0 && oact.sa_flags & SA_SIGINFO) {
            if (sip) {
                HV *sih = newHV();
                SV *rv  = newRV_noinc(MUTABLE_SV(sih));
                /* The siginfo fields signo, code, errno, pid, uid,
                 * addr, status, and band are defined by POSIX/SUSv3. */
                (void)hv_stores(sih, "signo", newSViv(sip->si_signo));
                (void)hv_stores(sih, "code", newSViv(sip->si_code));
#if 0 /* XXX TODO: Configure scan for the existence of these, but even that does not help if the SA_SIGINFO is not implemented according to the spec. */
                hv_stores(sih, "errno",      newSViv(sip->si_errno));
                hv_stores(sih, "status",     newSViv(sip->si_status));
                hv_stores(sih, "uid",        newSViv(sip->si_uid));
                hv_stores(sih, "pid",        newSViv(sip->si_pid));
                hv_stores(sih, "addr",       newSVuv(PTR2UV(sip->si_addr)));
                hv_stores(sih, "band",       newSViv(sip->si_band));
#endif
                EXTEND(SP, 2);
                PUSHs(rv);
                mPUSHp((char *)sip, sizeof(*sip));
            }
        }
    }
}

您想要的信息将在最后一个参数中,尽管您必须在 Perl 端自己解压缩 *sip。问题是上面的代码没有得到锻炼。具体来说,sip 始终是NULL


在不安全的信号下,sighandler 是从 Perl 的 C 级信号处理程序 csighandler 调用的。它目前不会将相关信息传递给signalhandler,但这很容易解决。

-Perl_csighandler(int sig, siginfo_t *sip PERL_UNUSED_DECL, void *uap PERL_UNUSED_DECL)
+Perl_csighandler(int sig, siginfo_t *sip, void *uap PERL_UNUSED_DECL)
-       (*PL_sighandlerp)(sig, NULL, NULL);
+       (*PL_sighandlerp)(sig, sip, NULL);

示例运行:

$ PERL_SIGNALS=unsafe ./perl -Ilib a.pl
31213
caught signal
$VAR1 = [
          'TERM',
          {
            'code' => 0,
            'signo' => 15
          },
          '...*sip as "packed/binary" string...'
        ];

在安全信号下,sighandler 通过PERL_ASYNC_CHECKdespatch_signals(原文如此)调用。不幸的是,csighandler 之前收到的*sip 不再可用。要解决此问题,csighandler 必须将*sip 的副本排队等待despatch_signals 获取。

【讨论】:

  • 是的,如果SA_SIGINFO 被定义并且feature pragma已开启。
  • 显然我正在查看 5.8.8 代码,5.14 似乎已经有很多需要做的事情,如您的代码所示。现在我的问题是为什么它在 5.14 中对我不起作用。
  • 我疯了,还是那段代码没有意义?它正在创建sih,在我看来它就像一个匿名 hashref,但它从不使用它。它会将sip 推入堆栈。
  • 没关系,我疯了,rv 是对sih 的引用,它被PUSHs 推入堆栈。
  • @Chas。 Owens,对于您的脚本,oact.sa_flags &amp; SA_SIGINFO4,但 sipNULL
猜你喜欢
  • 1970-01-01
  • 2015-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多