Làm thế nào tôi có thể kiểm tra những tín hiệu mà một quá trình đang lắng nghe?


81

Làm cách nào tôi có thể xác minh xem một quy trình đang chạy có bắt được tín hiệu hay bỏ qua hoặc chặn nó không? Lý tưởng nhất là tôi muốn xem danh sách các tín hiệu, hoặc ít nhất là không phải thực sự gửi tín hiệu để kiểm tra.

Câu trả lời:


109

Trong Linux, bạn có thể tìm thấy PID của quy trình của mình, sau đó xem xét /proc/$PID/status. Nó chứa các dòng mô tả tín hiệu nào bị chặn (SigBlk), bị bỏ qua (SigIgn) hoặc bị bắt (SigCgt).

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

Số ở bên phải là một bitmask. Nếu bạn chuyển đổi nó từ hex sang nhị phân, mỗi 1 bit đại diện cho tín hiệu bị bắt, đếm từ phải sang trái bắt đầu bằng 1. Vì vậy, bằng cách giải thích dòng SigCgt, chúng ta có thể thấy rằng initquá trình của tôi đang bắt được các tín hiệu sau:

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

(Tôi đã tìm thấy ánh xạ số-tên bằng cách chạy kill -ltừ bash.)

EDIT : Và theo nhu cầu phổ biến, một kịch bản, trong 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

2
Nếu một tín hiệu được liệt kê dưới SigBlknó cũng xuất hiện trong SigCgt? Bởi vì bằng cách chặn nó, nó chỉ có nghĩa là tín hiệu sẽ bị phẫn nộ một lát sau phải không và có cần phải bắt không?
CMCDragonkai

Không, bạn có thể chặn tín hiệu mà không sẵn sàng bắt nó. Nếu bạn không bắt được tín hiệu, một hành động mặc định sẽ xảy ra tùy thuộc vào tín hiệu (thường là quá trình chấm dứt). Nếu bạn muốn biết thêm chi tiết, bạn nên mở một câu hỏi.
Jander

Việc sử dụng phiên bản POSIX của tập lệnh đọc là /procgì? Nó chỉ hoạt động trên Linux ... Và localkhông phải là POSIX. Vâng, nó là như vậy, nhưng tác dụng của nó là "không xác định".
Kusalananda

2
@Kusalananda: Linux không ngụ ý Bash - ví dụ: các nền tảng nhúng nhỏ thường sử dụng Busybox - nhưng tuân thủ POSIX là một đảm bảo gần như cho bất kỳ hiện đại nào /bin/sh. Bạn nói đúng local; Tôi sẽ dọn sạch nó.
Jander

@Jander Điểm công bằng. Tôi thú nhận đã đưa ra một giả định vội vàng liên quan đến Bash và Linux.
Kusalananda

23

Trên Solaris, chạy psigtrên id tiến trình để nhận danh sách các tín hiệu và cách xử lý chúng.

Ví dụ:

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

cho thấy SIGHUP, SIGILL, v.v. đều sẽ bị bắt bởi cùng một chức năng xử lý tín hiệu termsig_sighandler, sẽ được chạy mà không sử dụng bất kỳ cờ nào có thể được đặt qua sigactionvà tất cả các tín hiệu sẽ được che dấu tạm thời trong khi xử lý tín hiệu đang chạy (trong trường hợp này là tất cả những cái sử dụng cùng một trình xử lý tín hiệu, vì vậy nó không được nhập lại trong khi đang chạy). Bạn cũng có thể thấy SIGQUIT & SIGTERM sẽ bị bỏ qua, SIGKILL & SIGPWR sử dụng các hành động tín hiệu mặc định của hệ thống và SIGCLD chỉ định cờ RESTART, do đó, nếu trình xử lý tín hiệu của nó làm gián đoạn cuộc gọi hệ thống, tòa nhà sẽ được khởi động lại.


Tuyệt vời! Tôi đã hy vọng ai đó sẽ thêm một câu trả lời không phải là Linux.
Jander

4

(Câu trả lời này tương tự như câu trả lời của @ user18096, ở chỗ nó tạo ra một tập lệnh xoay quanh câu trả lời của @ Jander's).

Tôi đã viết một psig scriptđể lấy một PID (hoặc tất cả các PID) và tạo đầu ra có thể đọc được của con người từ các mặt nạ tín hiệu /proc/<PID>/status.

Ví dụ đầu ra:

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

Hãy cẩn thận:

  • Đây một câu trả lời cụ thể của Linux.
  • Có thể cần một phiên bản Python tương đối mới để chạy tập lệnh, nó sử dụng withOrderedDict.

2

Tôi tiếp tục quay lại câu trả lời hay của @ Jander với hy vọng có bộ giải mã sao chép và dán khi gặp phải vấn đề như:

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

Đoán tôi sẽ phải gõ một cái gì đó ... nói:

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

Tôi muốn nó có thể dễ đọc hơn một chút, nhưng điều đó khiến nó trở nên vụng về hơn so với tôi muốn, vì vậy, nhờ đề xuất của @ alanc, tôi sẽ lưu nó dưới dạng ~ / bin / psig.


2

Sử dụng điều này(liên kết bị hỏng) thư viện này để có được thông tin về các công việc đang chạy.

Có một trường đặc biệt trong struct Jobcác tín hiệu, được gọi làsigCgt

Bạn có thể sử dụng một cái gì đó như thế này:

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

Tôi rất thích nhưng liên kết bị hỏng.
Michael Fox

1
@MichaelFox xem chỉnh sửa của tôi. Người dùng đã xóa tài khoản của mình. Liên kết mới trỏ đến cùng một dự án
LittleByBlue

1

Trên FreeBSD, sử dụng procstat -i <PID>để xem tín hiệu nào bị bỏ qua bởi quá trình. Tương tự, procstat -j <PID>để xem tín hiệu nào bị chặn bởi các luồng xử lý. Cả hai lệnh hiển thị nếu một tín hiệu đang chờ xử lý.

Đầu ra mẫu:

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

Xem Procstat (1) .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.