2011-06-09 8 views
37

En C, lo que puedo decir¿Cómo, en Perl 5, puedo obtener el pid del proceso que me envió una señal?

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

Esto muestra algo así como

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

cuando se envía un SIGTERM del proceso de 31985.

Puedo escribir semejante código Perl 5 utilizando 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; 

Pero el controlador aún solo recibe un argumento (la señal). ¿Cómo puedo obtener una estructura de siginfo_t? ¿Tengo que escribir mi propio código XS que configura su propio controlador y luego pasa la información a una devolución de llamada de Perl? ¿Escribo mi intérprete en XS de alguna manera?

+6

Ojalá pudiera votar esto más de una vez. Es una pregunta tremendamente excelente. ¿Has mirado el código XS existente desde el módulo POSIX? No lo he hecho, pero apuesto a que ahí reside la respuesta a su pregunta. En cuanto a atornillar el intérprete, ¿sabe usted que las "señales de seguridad" cambian al bucle del intérprete? – tchrist

+1

@tchrist Sí, sé sobre el cambio que sucedió en algún punto de la línea 5.8. Eso es algo de lo que me preocupaba. No sé cómo interactuar con cómo funciona eso. Leer las cosas de POSIX XS es ​​probablemente el camino a seguir. Esperaba que alguien ya hubiera hecho el trabajo duro por mí. –

+1

Si a @tchrist le gusta, eso es suficiente para mí: +1 –

Respuesta

19

sighandler (se encuentra en mg.c) es la envoltura alrededor del subministrador de señales Perl. Como puede ver, es capaz de enviar la información que desee al sub controlador de señales de 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)); 
      } 
     } 
    } 
} 

La información que desea estaría en el último parámetro, a pesar de que lo tienes que descomprimir *sip mismo Perl-lado. El problema es que el código anterior no se está ejecutando. Específicamente, sip es siempre NULL.


Bajo señales inseguras, sighandler se llama desde csighandler, manejador de la señal de nivel C de Perl. Actualmente no transmite la información pertinente al signalhandler, pero eso se soluciona fácilmente.

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

de ejecución de la muestra:

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

Bajo señales seguras, sighandler se llama desde despatch_signals (sic) a través de PERL_ASYNC_CHECK. Desafortunadamente, el *sip previamente recibido por csighandler ya no está disponible. Para solucionar esto, csighandler tendría que poner en cola una copia de *sip para despatch_signals para recuperar.

+1

Sí, he estado investigando qué se necesitaría para hacer que Perl 5.15 siempre pase un segundo arg con los datos de siginfo_t en un hashref para señalar a los manejadores si 'SA_SIGINFO' está definido y el pragma 'feature' está activado. –

+0

Aparentemente estaba viendo el código 5.8.8, 5.14 parece que ya tiene mucho de lo que se necesita hacer, como muestra su código. Ahora mi pregunta es por qué no funciona para mí en 5.14. –

+0

¿Estoy loco, o ese código no tiene sentido?Está creando 'sih' que me parece un hashref anónimo, pero nunca lo usa. Empuja 'sip' en la pila en su lugar. –

Cuestiones relacionadas