在Perl 5中,我如何获得向我发送信号的过程的pid?

时间:2021-08-03 15:50:51

In C, I can say

在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;
}

This prints out something like

这打印出类似的东西

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

when sent a SIGTERM from process 31985.

当从过程31985发送SIGTERM时。

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

我可以使用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;

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?

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

1 个解决方案

#1


19  

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.

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));
            }
        }
    }
}

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.

你想要的信息将在最后一个参数中,尽管你必须解包*自己啜饮Perl端。问题是上面的代码没有得到执行。具体来说,sip始终为NULL。


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.

在不安全的信号下,sighandler是从csighandler调用的,这是Perl的C级信号处理程序。它目前没有将相关信息传递给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);

Sample run:

样品运行:

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

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_ASYNC_CHECK从despatch_signals(sic)调用sighandler。不幸的是,之前由csighandler收到的* sip已不再可用。要解决此问题,csighandler必须将用于despatch_signals的* sip副本排队到fetch。

#1


19  

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.

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));
            }
        }
    }
}

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.

你想要的信息将在最后一个参数中,尽管你必须解包*自己啜饮Perl端。问题是上面的代码没有得到执行。具体来说,sip始终为NULL。


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.

在不安全的信号下,sighandler是从csighandler调用的,这是Perl的C级信号处理程序。它目前没有将相关信息传递给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);

Sample run:

样品运行:

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

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_ASYNC_CHECK从despatch_signals(sic)调用sighandler。不幸的是,之前由csighandler收到的* sip已不再可用。要解决此问题,csighandler必须将用于despatch_signals的* sip副本排队到fetch。