在 Perl 5 中,我如何获得向我发送信号的进程的 pid? [英] How, in Perl 5, can I get the pid of the process who sent me a signal?

查看:39
本文介绍了在 Perl 5 中,我如何获得向我发送信号的进程的 pid?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 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 时.

when sent a SIGTERM from process 31985.

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

I can write similar Perl 5 code using POSIX::sigaction:

#!/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 中编写我自己的处理程序会以某种方式搞砸解释器吗?

But the handler still only receives one argument (the signal). How can I get at siginfo_t structure? Do have to write my own XS code that sets up its own handler and then passes the information on to a Perl callback? Will writing my own handler in XS screw up the interpreter in some way?

推荐答案

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

sighandler (found in mg.c) is the wrapper around the Perl signal handler sub. As you can see, it is capabable of sending the information you want to the Perl signal handler sub.

#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.

The information you want would be in the last parameter, although you'd have to unpack *sip yourself Perl-side. The catch is that the above code isn't getting excercised. Specifically, sip is always NULL.

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

Under unsafe signals, sighandler is called from csighandler, Perl's C-level signal handler. It currently doesn't pass on the pertinent information to signalhandler, but that's easily fixed.

-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...'
        ];

<小时>

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


Under safe signals, sighandler is called from despatch_signals (sic) via PERL_ASYNC_CHECK. Unfortunately, the *sip previously received by csighandler is no longer available. To fix this, csighandler would have to queue a copy of *sip for despatch_signals to fetch.

这篇关于在 Perl 5 中,我如何获得向我发送信号的进程的 pid?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆