2011-06-09 113 views
37

在C,我可以说在Perl 5中,如何获得向我发送信号的进程的pid?

#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 

使用POSIX::sigaction从工艺31985.

我可以写类似的Perl 5代码发送SIGTERM时:

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

+6

我希望我能不止一次地对此赞不绝口。这是一个非常优秀的问题。您是否查看了POSIX模块中现有的XS代码?我没有,但我敢打赌,这是你问题的答案所在。至于搞砸解释器,你是否意识到解释器循环的“安全信号”改变? – tchrist 2011-06-09 16:53:51

+1

@tchrist是的,我知道在5.8行的某个点发生的变化。这就是我所担心的。我不知道如何连接这些东西的工作原理。阅读POSIX XS的东西可能是要走的路。我希望有人已经为我做了辛苦的工作。 – 2011-06-09 17:02:39

+1

如果@tchrist喜欢它,那对我来说已经足够了:+1 – 2011-06-09 17:12:05

回答

19

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

你想会是最后一个参数,虽然你拥有的信息解压*sip自己的Perl端。问题在于上面的代码没有得到行使。具体而言,sip总是NULL


在不安全的信号,sighandlercsighandler,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...' 
     ]; 

在安全信号,sighandlerdespatch_signals(原文如此)经由PERL_ASYNC_CHECK调用。不幸的是,之前csighandler收到的*sip已不再可用。为了解决这个问题,csighandler必须将*sip的副本排队以获取despatch_signals

+1

是的,我一直在研究如何让Perl 5.15总是通过hashref中的siginfo_t数据传递第二个参数来告诉处理程序,如果'SA_SIGINFO'被定义并且'特征'杂注打开。 – 2011-06-09 19:23:09

+0

显然我在看5.8.8的代码,5.14似乎已经有很多需要做的事情,就像你的代码显示的那样。现在我的问题是为什么它在5.14中不适合我。 – 2011-06-09 19:27:57

+0

我疯了吗,还是那个代码没有意义?它创建的'sih'在我看来就像一个匿名的hashref,但它从来没有使用它。它将堆叠上的“sip”压入。 – 2011-06-09 19:43:31