¿Cómo puedo verificar qué señales está escuchando un proceso?

81

¿Cómo puedo verificar si un proceso en ejecución captará una señal, la ignorará o la bloqueará? Idealmente, me gustaría ver una lista de señales, o al menos no tener que enviar la señal para verificar.

Jander
fuente

Respuestas:

109

En Linux, puede encontrar el PID de su proceso y luego mirarlo /proc/$PID/status. Contiene líneas que describen qué señales están bloqueadas (SigBlk), ignoradas (SigIgn) o capturadas (SigCgt).

# cat /proc/1/status
...
SigBlk: 0000000000000000
SigIgn: fffffffe57f0d8fc
SigCgt: 00000000280b2603
...

El número a la derecha es una máscara de bits. Si lo convierte de hexadecimal a binario, cada 1 bit representa una señal atrapada, contando de derecha a izquierda comenzando con 1. Entonces, al interpretar la línea SigCgt, podemos ver que mi initproceso está captando las siguientes señales:

00000000280b2603 ==> 101000000010110010011000000011
                     | |       | ||  |  ||       |`->  1 = SIGHUP
                     | |       | ||  |  ||       `-->  2 = SIGINT
                     | |       | ||  |  |`----------> 10 = SIGUSR1
                     | |       | ||  |  `-----------> 11 = SIGSEGV
                     | |       | ||  `--------------> 14 = SIGALRM
                     | |       | |`-----------------> 17 = SIGCHLD
                     | |       | `------------------> 18 = SIGCONT
                     | |       `--------------------> 20 = SIGTSTP
                     | `----------------------------> 28 = SIGWINCH
                     `------------------------------> 30 = SIGPWR

(Encontré el mapeo de número a nombre al ejecutar kill -ldesde bash).

EDITAR : Y por demanda popular, un script, en POSIX sh.

sigparse () {
    i=0
    # bits="$(printf "16i 2o %X p" "0x$1" | dc)" # variant for busybox
    bits="$(printf "ibase=16; obase=2; %X\n" "0x$1" | bc)"
    while [ -n "$bits" ] ; do
        i="$(expr "$i" + 1)"
        case "$bits" in
            *1) printf " %s(%s)" "$(kill -l "$i")" "$i" ;;
        esac
        bits="${bits%?}"
    done
}

grep "^Sig...:" "/proc/$1/status" | while read a b ; do
        printf "%s%s\n" "$a" "$(sigparse "$b")"
    done # | fmt -t  # uncomment for pretty-printing
Jander
fuente
2
Si una señal aparece debajo, SigBlk¿también aparece en SigCgt? Porque al bloquearlo, solo significa que la señal se reenviará un poco más tarde, ¿verdad y que hay que atraparla?
CMCDragonkai
No, puede bloquear una señal sin estar listo para captarla. Si no capta una señal, sucederá una acción predeterminada dependiendo de la señal (generalmente la finalización del proceso). Si desea más detalles, debe abrir una pregunta.
Jander
¿De qué sirve una versión POSIX de un script que lee /proc? Solo funcionará en Linux ... Y localno es POSIX. Bueno, es un poco, pero su efecto es "no especificado".
Kusalananda
2
@Kusalananda: Linux no implica Bash, por ejemplo, las pequeñas plataformas integradas a menudo usan Busybox, pero el cumplimiento de POSIX es una garantía cercana para cualquier moderno /bin/sh. Tienes razón sobre local; Lo limpiaré.
Jander
@Jander Fair point. Confieso haber hecho una suposición apresurada con respecto a Bash y Linux.
Kusalananda
23

En Solaris, ejecute psigla identificación del proceso para obtener una lista de señales y cómo se manejarán.

Por ejemplo:

bash-4.2$ psig $$
11088:  bash
HUP     caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
INT     caught  sigint_sighandler   0
QUIT    ignored
ILL     caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
TRAP    caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
ABRT    caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
EMT     caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
FPE     caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
KILL    default
BUS     caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
SEGV    caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
SYS     caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
PIPE    caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
ALRM    caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
TERM    ignored
USR1    caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
USR2    caught  termsig_sighandler  0   HUP,INT,ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,VTALRM,XCPU,XFSZ,LOST
CLD     blocked,caught  0x4898e8    RESTART
PWR     default
WINCH   caught  sigwinch_sighandler 0
[...]

que muestra que SIGHUP, SIGILL, etc., todos serán capturados por la misma función de controlador de señal termsig_sighandler, que se ejecutará sin usar ninguno de los indicadores que se pueden configurar a través de sigaction, y todas las señales que se enmascararán temporalmente mientras el controlador de señal esté en ejecución (en este caso, todos los que usan el mismo controlador de señal, por lo que no se vuelve a ingresar mientras ya se está ejecutando). También puede ver que SIGQUIT & SIGTERM serán ignorados, SIGKILL & SIGPWR usan las acciones de señal predeterminadas del sistema, y ​​SIGCLD especifica el indicador RESTART, por lo que si su manejador de señales interrumpe una llamada del sistema, la llamada al sistema se reiniciará.

alanc
fuente
¡Increíble! Esperaba que alguien agregara una respuesta que no sea Linux.
Jander
4

(Esta respuesta es similar a la respuesta de @ user18096, ya que crea un script alrededor de la respuesta de @ Jander).

He escrito un psig scriptpara tomar un PID (o todos los PID) y crear una salida legible por humanos a partir de las máscaras de señal /proc/<PID>/status.

Salida de ejemplo:

% ./psig -a
[     1] Signals Queued: 8/773737
[     1] Signals Pending:
[     1] Signals Pending (Shared):
[     1] Signals Blocked:
[     1] Signals Ignored: SIGPIPE
[     1] Signals Caught: SIGHUP,SIGINT,SIGABRT,SIGUSR1,SIGSEGV,SIGALRM,SIGTERM,SIGCHLD,SIGPWR
...
[ 31001] Signals Queued: 0/773737
[ 31001] Signals Pending:
[ 31001] Signals Pending (Shared):
[ 31001] Signals Blocked: SIGHUP,SIGINT,SIGQUIT,SIGILL,SIGTRAP,SIGABRT,SIGBUS,SIGFPE,SIGUSR1,SIGUSR2,SIGPIPE,SIGALRM,SIGTERM,SIGSTKFLT,SIGCHLD,SIGCONT,SIGTSTP,SIGTTIN,SIGTTOU,SIGURG,SIGXCPU,SIGXFSZ,SIGPROF,SIGWINCH,SIGIO,SIGPWR,SIGSYS,SIGRTMIN,SIGRTMIN+1,SIGRTMIN+2,SIGRTMIN+3,SIGRTMIN+4,SIGRTMIN+5,SIGRTMIN+6,SIGRTMIN+7,SIGRTMIN+8,SIGRTMIN+9,SIGRTMIN+10,SIGRTMIN+11,SIGRTMIN+12,SIGRTMIN+13,SIGRTMIN+14,SIGRTMIN+15,SIGRTMAX-14,SIGRTMAX-13,SIGRTMAX-12,SIGRTMAX-11,SIGRTMAX-10,SIGRTMAX-9,SIGRTMAX-8,SIGRTMAX-7,SIGRTMAX-6,SIGRTMAX-5,SIGRTMAX-4,SIGRTMAX-3,SIGRTMAX-2,SIGRTMAX-1,SIGRTMAX
[ 31001] Signals Ignored: SIGHUP,SIGINT,SIGQUIT,SIGPIPE,SIGXFSZ
[ 31001] Signals Caught: SIGBUS,SIGUSR1,SIGSEGV,SIGUSR2,SIGALRM,SIGTERM,SIGVTALRM

Advertencias:

  • Esta es una respuesta específica de Linux.
  • Es posible que necesite una versión de Python relativamente nueva para ejecutar el script, usa withy OrderedDict.
erik.weathers
fuente
2

Sigo volviendo a la bonita respuesta de @ Jander esperando un decodificador de copiar y pegar cuando me enfrento a:

user@machine:~$ grep Sig...: /proc/18475/status
SigPnd: 0000000000000000
SigBlk: fffffffe7dfbfaff
SigIgn: 0000000000001000
SigCgt: 0000000182006e47
user@machine:~$ 

Supongo que tendré que golpear algo ... decir:

user@machine:~$ ruby -wn - /proc/18475/status <<'EOF'
if $_.match(/Sig(Pnd|Blk|Ign|Cgt):\s([0-9a-f]{16})/) == nil
  next
end
field = $1
mask = $2.to_i(16)
names = []
Signal.list().each_pair() {
  |name, number|
  if number == 0
    # "EXIT" => 0
    next
  end
  if (mask & (1 << (number - 1))) == 0
    next
  end
  names << name
}
puts("Sig#{field}: #{names.join(" | ")}")
EOF
SigPnd: 
SigBlk: HUP | INT | QUIT | ILL | TRAP | IOT | ABRT | FPE | BUS | SYS | PIPE | ALRM | TERM | URG | TSTP | CONT | CHLD | CLD | TTIN | TTOU | IO | XCPU | XFSZ | PROF | WINCH | USR1 | USR2 | PWR | POLL
SigIgn: PIPE
SigCgt: HUP | INT | QUIT | BUS | SEGV | ALRM | TERM | VTALRM | USR1 | USR2
user@machine:~$ 

Quería que fuera algo legible, pero eso hace que invocar sea un poco más torpe de lo que quisiera, así que, gracias a la sugerencia de @ alanc, lo guardaré como ~ / bin / psig.

Martin Dorey
fuente
2

Utilizar esta(enlace roto) esta biblioteca para obtener información sobre los trabajos que se están ejecutando.

Hay un campo especial en el struct Jobpara las señales, llamadosigCgt

Puedes usar algo como esto:

#include"read_proc.h"
int main(void)
{
    struct Root * rt=read_proc();
    struct Job * jb=rt->first->job;
    printf("%ull\n",jb->sigCgt);
    return 0;
}
LittleByBlue
fuente
Me encantaría, pero el enlace está roto.
Michael Fox
1
@MichaelFox ver mi edición. El usuario ha eliminado su cuenta. El nuevo enlace apunta al mismo proyecto
LittleByBlue
1

En FreeBSD, use procstat -i <PID>para ver qué señales son ignoradas por el proceso. Del mismo modo, procstat -j <PID>para ver qué señales están bloqueadas por los subprocesos del proceso. Ambos comandos muestran si hay una señal pendiente.

Salida de muestra:

$ procstat -i 38540 PID COMM SIG FLAGS 38540 nsulfd HUP -I- 38540 nsulfd INT -I- 38540 nsulfd QUIT -I- 38540 nsulfd ILL --- 38540 nsulfd TRAP --- ...

$ procstat -j 38540 PID TID COMM SIG FLAGS 38540 101220 nsulfd HUP -- 38540 101220 nsulfd INT -- 38540 101220 nsulfd QUIT -B 38540 101220 nsulfd ILL -- 38540 101220 nsulfd TRAP -- ...

Ver procstat (1) .

Deepak
fuente