2011-06-09 68 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