Jak mogę sprawdzić, jakie sygnały słucha proces?

81

Jak mogę sprawdzić, czy uruchomiony proces złapie sygnał, zignoruje go lub zablokuje? Idealnie chciałbym zobaczyć listę sygnałów, a przynajmniej nie muszę wysyłać sygnału do sprawdzenia.

Jander
źródło

Odpowiedzi:

109

Pod Linuksem możesz znaleźć PID swojego procesu, a następnie spojrzeć na /proc/$PID/status. Zawiera wiersze opisujące, które sygnały są blokowane (SigBlk), ignorowane (SigIgn) lub przechwycone (SigCgt).

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

Liczba po prawej to maska ​​bitowa. Jeśli przekształcisz go z szesnastkowego na dwójkowy, każdy 1-bit reprezentuje przechwycony sygnał, licząc od prawej do lewej, zaczynając od 1. Tak więc interpretując linię SigCgt, możemy zobaczyć, że mój initproces przechwytuje następujące sygnały:

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

(Znalazłem mapowanie liczb na nazwy, uruchamiając kill -lz bash.)

EDYCJA : I na żądanie, skrypt w 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
źródło
2
Jeśli sygnał znajduje się na liście, SigBlkczy pojawia się również w SigCgt? Ponieważ blokowanie go oznacza po prostu, że sygnał zostanie wysłany nieco później, prawda i trzeba go złapać?
CMCDragonkai
Nie, możesz zablokować sygnał, nie będąc gotowym na jego złapanie. Jeśli nie złapiesz sygnału, nastąpi domyślna akcja w zależności od sygnału (zwykle zakończenie procesu). Jeśli chcesz uzyskać więcej szczegółów, powinieneś otworzyć pytanie.
Jander
Jaki jest pożytek z wersji POSIX odczytu skryptu /proc? Działa tylko w systemie Linux ... I localnie jest POSIX. Cóż, to trochę tak, ale jego efekt jest „nieokreślony”.
Kusalananda
2
@Kusalananda: Linux nie oznacza Bash - na przykład małe platformy wbudowane często używają Busybox - ale zgodność z POSIX jest niemal gwarancją dla każdego nowoczesnego /bin/sh. Masz rację local; Posprzątam to.
Jander
@Jander Fair point. Przyznaję, że pospiesznie zakładam Bash i Linux.
Kusalananda
23

W psigsystemie Solaris uruchom identyfikator procesu, aby uzyskać listę sygnałów i sposób ich obsługi.

Na przykład:

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
[...]

co pokazuje, że SIGHUP, SIGILL itp. zostaną przechwycone przez tę samą funkcję modułu obsługi sygnałów termsig_sighandler, która zostanie uruchomiona bez użycia żadnych flag, które można ustawić za pomocą sigaction, oraz wszystkie sygnały, które zostaną tymczasowo zamaskowane, gdy moduł obsługi sygnału jest działa (w tym przypadku wszystkie używają tej samej procedury obsługi sygnału, więc nie jest ponownie wprowadzane, gdy już działa). Możesz również zobaczyć, że SIGQUIT i SIGTERM zostaną zignorowane, SIGKILL i SIGPWR używają domyślnych akcji systemowych sygnału, a SIGCLD określa flagę RESTART, więc jeśli jego procedura obsługi sygnału przerwie wywołanie systemowe, syscall zostanie zrestartowany.

alanc
źródło
Niesamowite! Miałem nadzieję, że ktoś doda odpowiedź inną niż Linux.
Jander
4

(Ta odpowiedź jest podobna do odpowiedzi @ user18096, ponieważ tworzy skrypt wokół odpowiedzi @ Jander.)

Napisałem a, psig scriptaby wziąć PID (lub wszystkie PID) i stworzyć czytelne dla człowieka wyjście z masek sygnałowych /proc/<PID>/status.

Przykładowe dane wyjściowe:

% ./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

Ostrzeżenia:

  • To jest odpowiedź specyficzna dla systemu Linux.
  • Może potrzebować stosunkowo nowej wersji Pythona do uruchomienia skryptu, używa withi OrderedDict.
erik.weathers
źródło
2

Wciąż wracam do ładnej odpowiedzi @ Jander, mając nadzieję na dekoder kopiuj-wklej, gdy widzę coś takiego:

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

Chyba będę musiał coś podrzucić ... powiedzieć:

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:~$ 

Chciałem, aby było to trochę czytelne, ale to spowodowało, że nieco trudniej było go wywoływać, niż chciałbym, więc dzięki sugestii @ alanc, zapiszę go jako ~ / bin / psig.

Martin Dorey
źródło
2

Posługiwać się to(uszkodzony link) ta biblioteka, aby uzyskać informacje o uruchomionych zadaniach.

W struct Jobsygnałach znajduje się specjalne pole , zwanesigCgt

Możesz użyć czegoś takiego:

#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
źródło
Chciałbym, ale link jest zepsuty.
Michael Fox,
1
@MichaelFox zobacz moją edycję. Użytkownik usunął swoje konto. Nowy link wskazuje na ten sam projekt
LittleByBlue,
1

W FreeBSD użyj, procstat -i <PID>aby zobaczyć, które sygnały są ignorowane przez proces. Podobnie, procstat -j <PID>aby zobaczyć, które sygnały są blokowane przez wątki procesu. Oba polecenia pokazują, czy sygnał oczekuje.

Przykładowe dane wyjściowe:

$ 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 -- ...

Zobacz procstat (1) .

Deepak
źródło