在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
。
我可以使用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代码来设置自己的处理程序,然后将这些信息传递给Perlcallback函数? 在XS中编写我自己的处理程序在某种程度上搞砸了解释器吗?
sighandler
(在mg.c
find)是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)); } } } }
你想要的信息将在最后一个参数,尽pipe你必须解压缩自己的Perl端。 问题在于上面的代码没有被执行。 具体来说, sip
总是NULL
。
在不安全的信号下, 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);
样品运行:
$ PERL_SIGNALS=unsafe ./perl -Ilib a.pl 31213 caught signal $VAR1 = [ 'TERM', { 'code' => 0, 'signo' => 15 }, '...*sip as "packed/binary" string...' ];
在安全信号下, sighandler
通过PERL_ASYNC_CHECK
从PERL_ASYNC_CHECK
(sic)中PERL_ASYNC_CHECK
。 不幸的是,以前由csighandler
收到的*sip
不再可用。 为了解决这个问题, csighandler
将不得不排队*sip
的拷贝以获取csighandler
。