Signal và Trap trong Unix/Linux

Signals là các tín hiệu ngắt phần mềm được gửi tới một chương trình báo rằng có một sự kiện nghiêm trọng đã xảy ra. Các sự kiện này có thể rất đa dạng từ các yêu cầu người sử dụng truy cập vào bộ nhớ bất hợp pháp. 

Một vài signal, như signal ngắt, chỉ rằng một người sử dụng đã đòi hỏi chương trình làm cái gì đó mà không trong sự kiểm soát. Bảng dưới đây liệt kê các signal thông thường mà bạn có thể bắt gặp hoặc muốn sử dụng nó trong các chương trình của bạn:

Tên signal
Số hiệu signal
Miêu tả
SIGHUP
1
Trì hoãn việc kiểm tra trên quản lý terminal hoặc sự dừng của quản lý tiến trình.
SIGINT
2
Được thông báo nếu người sử dụng gửi một tín hiệu ngắt (Ctrl+C).
SIGQUIT
3
Được thông báo nếu người sử dụng gửi một tín hiệu bỏ (Ctrl+D).
SIGFPE
8
Được thông báo nếu một hoạt động thuộc về toán không hợp pháp được thử chạy.
SIGKILL
9
Nếu một tiến trình nhận signal này, nó phải thoát ra ngay lập tức và sẽ không thực hiện các hoạt động làm sạch.
SIGALRM
14
Tín hiệu báo số lần thực hiện (Alarm Clock).
SIGTERM
15
Tín hiệu kết thúc phần mềm (được gửi bởi sigkill theo mặc định).

Danh sách các signal trong Unix/Linux

Có một cách dễ dàng để liệt kê tất cả các signal được hỗ trợ bởi hệ thống của bạn. Chỉ cần thông báo lệnh kill -l và nó sẽ hiển thị tất cả các signal được hỗ trợ.

$ 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

Danh sách thực tế trên của signal là đa dạng và khác nhau giữa Solaris, HP-UX và Linux.

Các hoạt động mặc định trong Unix/Linux

Mỗi signal có một hoạt động mặc định liên kết với nó. Hoạt động mặc định với một signal là hoạt động mà một script hoặc một chương trình thực hiện khi nó nhận được một signal. Một trong số các hoạt động mặc định có thể là:

  • Kết thúc tiến trình
  • Bỏ qua signal
  • Kết xuất lõi nhớ. Nó tạo một file gọi là core (lõi) chứa hình ảnh bộ nhớ của tiến trình khi nó nhận được signal
  • Dừng tiến trình
  • Tiếp tục tiến trình bị dừng

Gửi các signal trong Unix/Linux

Có một vài phương thức trong việc gửi các signal tới một chương trình hoặc một script. Một trong những phương thức phổ biến nhất là cho người sử dụng gõ phím Ctrl +C hoặc phím dừng trong khi một script đang chạy. Khi bạn nhấn phím Ctrl+C, một SIGINT được gửi tới script và khi mỗi hành động mặc định đã xác định sẽ kết thúc script. Phương thức phổ biến khác để gửi signal là sử dụng lệnh kill mà có cú pháp như sau:

$ kill -signal pid

Ở đây, signal là hoặc số hoặc tên của signal để gửi và pid là ID tiến trình mà signal nên được gửi tới. Ví dụ:

$ kill -1 1001

Gửi HUP hoặc signal dừng tới một chương trình mà đang chạy với ID tiến trình là 1001. Để gửi một kill signal tới tiến trình giống như vậy, bạn sử dụng lệnh sau:

$ kill -9 1001

Nó sẽ hủy tiến trình đang chạy có ID tiến trình 1001.

Trap signal trong Unix/Linux

Khi bạn nhấn phím Ctrl+C hoặc phím dừng tại terminal của bạn trong suốt quá trình chạy một chương trình shell, thông thường thì chương trình đó bị ngay lập tức kết thúc, và dòng nhắc lệnh xuất hiện trở lại. Việc này có thể sẽ không luôn luôn làm bạn thích thú. Ví dụ, bạn có thể sẽ để lại hàng loạt các tập tin tạm thời mà không được dọn sạch. Trap signal là khá dễ dàng, và lệnh trap có cú pháp như sau:

$ trap commands signals

Ở đây, command có thể là bất cứ lệnh Unix có hiệu lực nào, hoặc ngay cả là một chức năng đã định nghĩa của người sử dụng, và signal có thể là danh sách các signal mà bạn muốn trap. Có 3 cách sử dụng phổ biến để trap trong shell script:

  1. Dọn sạch các file tạm thời
  2. Bỏ qua các signal

Dọn sạch các file tạm thời trong Unix/Linux

Như một ví dụ của lệnh trap, dưới đây chỉ cách bạn có thể gỡ bỏ một vài file và sau đó thoát khỏi nếu ai đó cố gắng bỏ dở chương trình từ terminal.

$ trap "rm -f $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 2

Từ điểm trong chương trình shell mà trap này được thực thi, hai tệp work1$$dataout$$ sẽ tự động bị dỡ bỏ nếu signal số 2 được nhận bởi chương trình. Vì thế nếu người sử dụng ngắt việc thi hành của chương trình thì sau đó trap này được chạy, bạn có thể được đảm bảo chắc chắn rằng hai file này sẽ được dọn sạch sẽ. Lệnh exit mà theo sau bởi rm là cần thiết bởi vì không có nó thì chương trình sẽ tiếp tục chạy tại điểm mà nó dừng lại khi signal được nhận. Signal số 1 được tạo để trì hoãn: hoặc ai đó cố tình treo dòng hoặc dòng một cách ngẫu nhiên bị ngắt kết nối. Bạn có thể chỉnh sửa trap trước để cũng gỡ bỏ hai file đã xác định trong trường hợp này bằng cách thêm signal số 1 tới danh sách các signal.

$ trap "rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 1 2

Bây giờ những file này sẽ bị gỡ bỏ nếu dòng bị treo hoặc nếu phím Ctrl+C được nhấn. Lệnh được xác định để trap phải được bao quanh trong trích dẫn nếu chúng chứa nhiều hơn một lệnh. Bạn cũng lưu ý rằng shell quét dòng lệnh tại thời điểm mà lệnh trap được chạy và cũng thưc hiện quét lần nữa khi một trong các signal được liệt kê được nhận. Vì thế trong ví dụ trước, giá trị của WORKDIR và $$ sẽ được thay đổi tại thời gian mà lệnh trap được chạy. Nếu bạn muốn sự thay đổi này xảy ra tại thời điểm mà hoặc signal số 1 hoặc số 2 được nhận, bạn có thể đặt các lệnh bên trong trích dẫn đơn như sau:

$ trap 'rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit' 1 2

Bỏ qua các signal trong Unix/Linux

Nếu lệnh được liệt kê cho trap là null, thì signal được xác định sẽ bị bỏ qua khi được nhận. Ví dụ, lệnh sau:

$ trap '' 2

Xác định rằng signal ngắt bị bỏ qua. Bạn có thể muốn bỏ qua các signal cụ thể nào đó khi thực hiện một số hoạt động mà mà không muốn bị ngắt. Bạn có thể xác định nhiều signal bị bỏ qua như sau:

$ trap '' 1 2 3 15

Ghi nhớ rằng đối số thứ nhất phải được xác định cho một signal để bị bỏ qua và cách trên là không cân bằng với cách viết sau, mà cách viết sau này có ý nghĩa riêng của nó:

$ trap  2

Nếu bạn bỏ qua một signal, tất cả các shell phụ cũng bỏ qua signal đó. Tuy nhiên, nếu bạn xác định một hành động được thực hiện khi nhận được signal thì tất cả các shell phụ cũng sẽ vẫn thực hiện hành động đó khi nhận được signal đó.

Thiết lập lại trap trong Unix/Linux

Sau khi bạn đã thay đổi các hành động mặc định khi nhận được một signal, bạn có thể thay đổi trở lại lần nữa với trap, nếu bạn đơn giản bỏ qua đối số đầu tiên như sau:

$ trap 1 2

Nó thiết lập lại hành động được thực hiện khi nhận được signal số 1 hoặc 2 trở lại dạng mặc định.

Bình luận