Saturday, 16 November 2019

kill - signal trên OS: SIGINT vs SIGTERM vs SIGKILL vs SIGHUP

kill

Lệnh kill không lạ gì với người dùng Linux/MacOS. Ngay từ những ngày đầu học dùng dòng lệnh trên các hệ điều hành này, người dùng đã biết dùng kill để "giết" một chương trình đang chạy (một process).

Câu lệnh này quá cơ bản, dẫn đến dễ bị bỏ qua việc tìm hiểu nó kỹ càng.



Để kill 1 chương trình đang chay, người dùng sẽ tìm PID (process ID - một số nguyên dương được hệ điều hành cấp cho chương trình lúc bắt đầu chạy) bằng lệnh:
ps xau | grep tên_chương_trình

Ví dụ:

$ ps xau | grep -i firefox
hvn      12537  8.9  4.4 3202268 358612 ?      Sl   23:17   0:47 /home/hvn/Downloads/firefox/firefox-bin


12537 chính là số PID. Sau đó gõ lệnh:

kill 12537

và nếu chương trình vẫn chạy, thì dùng biện pháp mạnh:

kill -9 12537 

sẽ đảm bảo nhanh, gọn, sạch sẽ, xong.

Nhưng bên dưới là cả một chủ đề không quá đơn giản đến vậy.


$ whatis kill; dpkg -S `which kill`
kill (1)             - send a signal to a process
kill (2)             - send signal to a process
procps: /bin/kill

Vậy kill không phải là để "giết chết 1 process" mà thực ra nó gửi 1 signal (tín hiệu) tới một process.

Trong Description của man 1 kill có ghi:

The default signal for kill is TERM.  Use -l or -L to list available signals.  Particularly useful signals include HUP, INT, KILL, STOP, CONT, and 0.  Alternate  signals may be specified in three ways: -9, -SIGKILL or -KILL.  Negative PID values may be used to choose whole process groups; see the PGID column in ps command output.  A PID  of -1 is special; it indicates all processes except the kill process itself and init.

Thay vì kiểu gõ dùng số như kill -9, có thể gõ rõ tên signal ra, như kill -SIGKILL

Các signal phổ biến TERM KILL HUP INT
- Khi chỉ gõ kill PID, kill sẽ mặc định gửi đi signal TERM (terminate) hay gọi là SIGTERM.
- kill -9 PID sẽ gửi đi SIGKILL tới PID
- SIGHUP (hang up) được gửi tới process khi process điều khiển bị đứt/ngắt (ví dụ đang SSH vào chạy lệnh thì đứt mạng)
- SIGINT (interrupt) được gửi khi user đang chạy chương trình thì bấm Ctrl-C

SIGTERM khác gì SIGKILL?

> Unlike SIGKILL, this signal can be blocked, handled, and ignored. It is the normal way to politely ask a program to terminate.
https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html

Process đang chạy khi nhận được SIGTERM sẽ hiểu là được yêu cầu kết thúc một cách lịch sự, chương trình thường sẽ dọn dẹp / đóng các tài nguyên đang sử dụng rồi thoát. Lập trình viên cũng có thể làm gì tùy ý, hoặc không làm gì cả. Yêu cầu là  việc của ông còn làm hay không thì  không phải việc của ông.
Đây là lý do nhiều khi kill PID không đủ, phải kill -9

SIGKILL

> The SIGKILL signal is used to cause immediate program termination. It cannot be handled or ignored, and is therefore always fatal. It is also not possible to block this signal.
> In fact, if SIGKILL fails to terminate a process, that by itself constitutes an operating system bug which you should report.


Người dùng gửi SIGKILL để kết thúc chương trình ngay lập tức, chữ KILL ở đây ám chỉ process sẽ không thể làm gì được, thậm chí là không biết. SIGKILL được hệ điều hành xử lý và nếu nó không kết thúc chương trình ngay, sẽ được xem như là một bug cần sửa của hệ điều hành.

SIGINT

Khi chạy chương trình bằng dòng lệnh, người dùng bấm Ctrl-C để gửi SIGINT tới chương trình, chương trình sẽ nhận được signal này và tùy ý xử lý, thường là sẽ dừng chương trình lại giống SIGTERM. Có thể dùng kill -2 hay kill -SIGINT để gửi signal này.

Làm thế nào để tiếp tục chạy 1 chương trình mà có thể ngắt kết nối SSH?

Vấn đề này thường được "vượt qua" bằng cách dùng chương trình tmux/screen sau khi SSH vào máy khác, dù mạng sau đó có đứt, thì chương trình vẫn chạy bình thường.
Một giải pháp CHỦ ĐỘNG hơn, là dùng câu lệnh nohup. Ví dụ:
nohup sleep 1000
để vẫn tiếp chạy câu lệnh sleep 1000 dù mạng có đứt khi SSH.
Nhưng nếu quên vào tmux, screen, quên cả nohup thì làm sao? Toang rồi!
Chưa! nếu dùng bash, có 1 câu lệnh builtin tên là disown sẽ giúp "bảo kê" chương trình đang chạy khỏi SIGHUP.

Trích man 1 bash

       The shell exits by default upon receipt of a SIGHUP.  Before exiting, an interactive shell  resends  the  SIGHUP  to all jobs, running or stopped.  Stopped jobs are sent SIGCONT to ensure that they receive the SIGHUP.  To prevent the shell  from  sending the  signal  to  a particular job, it should be removed from the jobs table with the disown builtin (see SHELL BUILTIN COMMANDS below) or marked to  not  receive  SIGHUP using disown -h.

Các signal - không hề đơn giản, có tới 69-5 signal!!!

$ kill -L
 1) SIGHUP     2) SIGINT     3) SIGQUIT     4) SIGILL     5) SIGTRAP
 6) SIGABRT     7) SIGBUS     8) SIGFPE     9) SIGKILL    10) SIGUSR1
11) SIGSEGV    12) SIGUSR2    13) SIGPIPE    14) SIGALRM    15) SIGTERM
16) SIGSTKFLT    17) SIGCHLD    18) SIGCONT    19) SIGSTOP    20) SIGTSTP
21) SIGTTIN    22) SIGTTOU    23) SIGURG    24) SIGXCPU    25) SIGXFSZ
26) SIGVTALRM    27) SIGPROF    28) SIGWINCH    29) SIGIO    30) SIGPWR
31) SIGSYS    34) SIGRTMIN    35) SIGRTMIN+1    36) SIGRTMIN+2    37) SIGRTMIN+3
38) SIGRTMIN+4    39) SIGRTMIN+5    40) SIGRTMIN+6    41) SIGRTMIN+7    42) SIGRTMIN+8
43) SIGRTMIN+9    44) SIGRTMIN+10    45) SIGRTMIN+11    46) SIGRTMIN+12    47) SIGRTMIN+13
48) SIGRTMIN+14    49) SIGRTMIN+15    50) SIGRTMAX-14    51) SIGRTMAX-13    52) SIGRTMAX-12
53) SIGRTMAX-11    54) SIGRTMAX-10    55) SIGRTMAX-9    56) SIGRTMAX-8    57) SIGRTMAX-7
58) SIGRTMAX-6    59) SIGRTMAX-5    60) SIGRTMAX-4    61) SIGRTMAX-3    62) SIGRTMAX-2
63) SIGRTMAX-1    64) SIGRTMAX   


Thực hiện trên
$ lsb_release -a; dpkg-query --show procps
No LSB modules are available.
Distributor ID:    Ubuntu
Description:    Ubuntu 18.04.3 LTS
Release:    18.04
Codename:    bionic
procps    2:3.3.12-3ubuntu1.1

Tham khảo:
- man 7 signal
- man 1 kill
- https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html


Hết.
HVN at https://pymi.vn and https://www.familug.org.

No comments:

Post a Comment