SIGINT liên quan như thế nào đến các tín hiệu kết thúc khác như SIGTERM, SIGQUIT và SIGKILL?


103

Trên hệ thống POSIX, các tín hiệu kết thúc thường có thứ tự sau (theo nhiều trang MAN và Thông số POSIX):

  1. SIGTERM - lịch sự yêu cầu một quá trình kết thúc. Nó sẽ kết thúc một cách duyên dáng, dọn dẹp tất cả các tài nguyên (tệp, ổ cắm, quy trình con, v.v.), xóa các tệp tạm thời, v.v.

  2. SIGQUIT - yêu cầu mạnh mẽ hơn. Nó sẽ chấm dứt sự vô phúc, vẫn dọn dẹp các tài nguyên thực sự cần dọn dẹp, nhưng có thể không xóa các tệp tạm thời, có thể viết thông tin gỡ lỗi ở đâu đó; trên một số hệ thống cũng sẽ ghi một kết xuất lõi (bất kể tín hiệu có được ứng dụng bắt hay không).

  3. SIGKILL - yêu cầu mạnh mẽ nhất. Quá trình này thậm chí không được yêu cầu làm bất cứ điều gì, nhưng hệ thống sẽ dọn dẹp quá trình, cho dù có như vậy hay không. Nhiều khả năng một kết xuất lõi được viết.

Làm thế nào để SIGINT phù hợp với bức tranh đó? Quá trình CLI thường bị SIGINT kết thúc khi người dùng nhấn CRTL + C, tuy nhiên, quá trình nền cũng có thể bị SIGINT kết thúc bằng cách sử dụng tiện ích KILL. Những gì tôi không thể thấy trong thông số kỹ thuật hoặc tệp tiêu đề là liệu SIGINT có mạnh hơn hay ít hơn SIGTERM hoặc nếu có bất kỳ sự khác biệt nào giữa SIGINT và SIGTERM.

CẬP NHẬT:

Mô tả tốt nhất về các tín hiệu kết thúc mà tôi tìm thấy cho đến nay là trong Tài liệu GNU LibC . Nó giải thích rất rõ rằng có sự khác biệt dự kiến ​​giữa SIGTERM và SIGQUIT.

Nó nói về SIGTERM:

Đó là cách bình thường để yêu cầu một chương trình chấm dứt một cách lịch sự.

Và nó nói về SIGQUIT:

[...] và tạo ra một kết xuất lõi khi nó kết thúc quá trình, giống như một tín hiệu lỗi chương trình. Bạn có thể coi đây là tình trạng lỗi chương trình được người dùng “phát hiện”. [...] Tốt nhất bạn nên bỏ qua một số loại dọn dẹp khi xử lý SIGQUIT. Ví dụ: nếu chương trình tạo các tệp tạm thời, nó sẽ xử lý các yêu cầu chấm dứt khác bằng cách xóa các tệp tạm thời. Nhưng tốt hơn hết là SIGQUIT không nên xóa chúng, để người dùng có thể kiểm tra chúng cùng với kết xuất lõi.

Và SIGHUP cũng được giải thích đủ rõ. SIGHUP không thực sự là một tín hiệu kết thúc, nó chỉ có nghĩa là "kết nối" với người dùng đã bị mất, vì vậy ứng dụng không thể mong đợi người dùng đọc thêm bất kỳ đầu ra nào (ví dụ: đầu ra stdout / stderr) và không có đầu vào để mong đợi từ người dùng nữa. Đối với hầu hết các ứng dụng có nghĩa là chúng tốt hơn nên thoát. Về lý thuyết, một ứng dụng cũng có thể quyết định rằng nó chuyển sang chế độ daemon khi nhận được SIGHUP và hiện đang chạy như một quy trình nền, ghi đầu ra vào tệp nhật ký đã định cấu hình. Đối với hầu hết các daemon đã chạy ở chế độ nền, SIGHUP thường có nghĩa là chúng sẽ kiểm tra lại các tệp cấu hình của mình, vì vậy bạn gửi nó đến các quy trình nền sau khi chỉnh sửa tệp cấu hình.

Tuy nhiên, không có giải thích hữu ích nào về SIGINT trên trang này, ngoài việc nó được gửi bởi CRTL + C. Có lý do gì khiến người ta xử lý SIGINT theo cách khác với SIGTERM không? Nếu vậy thì lý do này là gì và cách xử lý sẽ khác như thế nào?


1
Câu hỏi hay. Tôi nghi ngờ một số sự cố Unix lịch sử sẽ tham gia vào câu trả lời.
Alex B

Tôi biết câu hỏi này đã cũ, nhưng trong trường hợp có ai đó đến đây để tìm danh sách đầy đủ các tín hiệu cho Hệ điều hành (Linux) của bạn, bạn có thể tìm thấy chúng bằng cách gõ sudo fuser -lvào dấu nhắc lệnh của bạn. Đối với tôi điều này gợi lên:HUP INT QUIT ILL TRAP ABRT IOT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH IO PWR SYS UNUSED
Nick Bull

3
Cũng thử kill -lcho một danh sách các tín hiệu.
AAAfarmclub

Câu trả lời:


88

SIGTERM và SIGKILL nhằm mục đích chung cho các yêu cầu "chấm dứt quá trình này". SIGTERM (theo mặc định) và SIGKILL (luôn luôn) sẽ khiến quá trình kết thúc. SIGTERM có thể bị bắt bởi quá trình (ví dụ như để nó có thể tự dọn dẹp nếu nó muốn), hoặc thậm chí bị bỏ qua hoàn toàn; nhưng SIGKILL không thể bị bắt hoặc bỏ qua.

SIGINT và SIGQUIT được thiết kế đặc biệt cho các yêu cầu từ thiết bị đầu cuối: các ký tự đầu vào cụ thể có thể được chỉ định để tạo ra các tín hiệu này (tùy thuộc vào cài đặt điều khiển đầu cuối). Hành động mặc định cho SIGINT là loại kết thúc quy trình giống như hành động mặc định cho SIGTERM và hành động không thể thay đổi đối với SIGKILL; hành động mặc định cho SIGQUIT cũng là kết thúc quá trình, nhưng các hành động bổ sung do triển khai xác định có thể xảy ra, chẳng hạn như tạo ra một kết xuất lõi. Quá trình này có thể bị bắt hoặc bỏ qua nếu được yêu cầu.

SIGHUP, như bạn nói, nhằm chỉ ra rằng kết nối đầu cuối đã bị mất, chứ không phải là một tín hiệu kết thúc như vậy. Tuy nhiên, một lần nữa, hành động mặc định cho SIGHUP (nếu quá trình không bắt hoặc bỏ qua nó) là chấm dứt quá trình theo cách tương tự như SIGTERM, v.v.

Có một bảng trong định nghĩa POSIXsignal.h liệt kê các tín hiệu khác nhau và các hành động và mục đích mặc định của chúng và chương Giao diện đầu cuối chung bao gồm nhiều chi tiết hơn về các tín hiệu liên quan đến thiết bị đầu cuối.


10
Đây là điểm mấu chốt: SIGINT và SIGQUIT có thể được tạo từ terminal bằng cách sử dụng các ký tự đơn, trong khi chương trình đang chạy. Các tín hiệu khác phải được tạo ra bởi một chương trình khác, bằng cách nào đó (ví dụ: bằng lệnh kill). SIGINT ít bạo lực hơn SIGQUIT; cái sau tạo ra một kết xuất lõi. SIGKILL không thể bị mắc kẹt. SIGHUP được tạo nếu kết nối của bạn bị treo (cửa sổ đóng, v.v.). Vì vậy, chúng đều có ý nghĩa khác nhau.
Jonathan Leffler

TTY Demystified có một số thông tin dễ hiểu về cách các tín hiệu tương tác với hệ thống con tty của hạt nhân. Thêm một số ngữ cảnh vào câu trả lời của bạn.
Daniel Näslund

1
Có vẻ như các thông số kỹ thuật không chính xác lắm, nhưng sự hiểu biết của tôi là SIgint yêu cầu chương trình dừng hành động hiện tại, không nhất thiết phải thoát. Đối với một chương trình chỉ được thiết kế thực hiện một hành động cho mỗi lần chạy ngụ ý làm chậm, nhưng đối với một chương trình tương tác có một số loại vòng lặp đọc-đánh giá-in, điều đó có thể có nghĩa là từ bỏ đánh giá hiện tại và quay lại đọc đầu vào của người dùng. Tôi nghĩ ít làm điều đó hơn trên sigint.
bdsl

Tín hiệu nào được gửi trong quá trình khởi động lại?
Dan Dascalescu

10

Như DarkDust đã lưu ý rằng nhiều tín hiệu có kết quả giống nhau, nhưng các quy trình có thể gắn các hành động khác nhau với chúng bằng cách phân biệt cách mỗi tín hiệu được tạo ra. Nhìn vào mã nguồn hạt nhân FreeBSD (kern_sig.c), tôi thấy rằng hai tín hiệu được xử lý theo cùng một cách, chúng kết thúc quá trình và được chuyển đến bất kỳ luồng nào.

SA_KILL|SA_PROC,             /* SIGINT */
SA_KILL|SA_PROC,             /* SIGTERM */

9

man 7 signal

Đây là trang chủ thuận tiện phi quy chuẩn của dự án trang nhân sự Linux mà bạn thường muốn xem để biết thông tin tín hiệu Linux.

Phiên bản 3.22 đề cập đến những điều thú vị như:

Các tín hiệu SIGKILL và SIGSTOP không thể bị bắt, bị chặn hoặc bị bỏ qua.

và chứa bảng:

Signal     Value     Action   Comment
----------------------------------------------------------------------
SIGHUP        1       Term    Hangup detected on controlling terminal
                              or death of controlling process
SIGINT        2       Term    Interrupt from keyboard
SIGQUIT       3       Core    Quit from keyboard
SIGILL        4       Core    Illegal Instruction
SIGABRT       6       Core    Abort signal from abort(3)
SIGFPE        8       Core    Floating point exception
SIGKILL       9       Term    Kill signal
SIGSEGV      11       Core    Invalid memory reference
SIGPIPE      13       Term    Broken pipe: write to pipe with no
                              readers
SIGALRM      14       Term    Timer signal from alarm(2)
SIGTERM      15       Term    Termination signal
SIGUSR1   30,10,16    Term    User-defined signal 1
SIGUSR2   31,12,17    Term    User-defined signal 2
SIGCHLD   20,17,18    Ign     Child stopped or terminated
SIGCONT   19,18,25    Cont    Continue if stopped
SIGSTOP   17,19,23    Stop    Stop process
SIGTSTP   18,20,24    Stop    Stop typed at tty
SIGTTIN   21,21,26    Stop    tty input for background process
SIGTTOU   22,22,27    Stop    tty output for background process

trong đó tóm tắt tín hiệu Actionphân biệt ví dụ: SIGQUIT với SIGQUIT, vì SIGQUIT có hành động Corevà SIGINTTerm .

Các hành động được ghi lại trong cùng một tài liệu:

The entries in the "Action" column of the tables below specify the default disposition for each signal, as follows:

Term   Default action is to terminate the process.

Ign    Default action is to ignore the signal.
Core   Default action is to terminate the process and dump core (see core(5)).
Stop   Default action is to stop the process.
Cont   Default action is to continue the process if it is currently stopped.

Tôi không thể thấy bất kỳ sự khác biệt nào giữa SIGTERM và SIGINT từ quan điểm của hạt nhân vì cả hai đều có hành động Termvà cả hai đều có thể bị bắt. Có vẻ như đó chỉ là "sự phân biệt quy ước sử dụng chung":

  • SIGINT là những gì sẽ xảy ra khi bạn thực hiện CTRL-C từ thiết bị đầu cuối
  • SIGTERM là tín hiệu mặc định được gửi bởi kill

Một số tín hiệu là ANSI C và những tín hiệu khác thì không

Một sự khác biệt đáng kể là:

  • SIGINT và SIGTERM là ANSI C, do đó dễ di chuyển hơn
  • SIGQUIT và SIGKILL không

Chúng được mô tả trong phần "7.14 Xử lý tín hiệu" của bản nháp C99 N1256 :

  • SIGINT nhận tín hiệu chú ý tương tác
  • SIGTERM một yêu cầu chấm dứt được gửi đến chương trình

điều này làm cho SIGINT trở thành một ứng cử viên sáng giá cho Ctrl + C tương tác.

POSIX 7

POSIX 7 ghi lại các tín hiệu với signal.htiêu đề: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html

Trang này cũng có bảng quan tâm sau đây đề cập đến một số điều chúng tôi đã thấy trong man 7 signal:

Signal    Default Action   Description
SIGABRT   A                Process abort signal.
SIGALRM   T                Alarm clock.
SIGBUS    A                Access to an undefined portion of a memory object.
SIGCHLD   I                Child process terminated, stopped,
SIGCONT   C                Continue executing, if stopped.
SIGFPE    A                Erroneous arithmetic operation.
SIGHUP    T                Hangup.
SIGILL    A                Illegal instruction.
SIGINT    T                Terminal interrupt signal.
SIGKILL   T                Kill (cannot be caught or ignored).
SIGPIPE   T                Write on a pipe with no one to read it.
SIGQUIT   A                Terminal quit signal.
SIGSEGV   A                Invalid memory reference.
SIGSTOP   S                Stop executing (cannot be caught or ignored).
SIGTERM   T                Termination signal.
SIGTSTP   S                Terminal stop signal.
SIGTTIN   S                Background process attempting read.
SIGTTOU   S                Background process attempting write.
SIGUSR1   T                User-defined signal 1.
SIGUSR2   T                User-defined signal 2.
SIGTRAP   A                Trace/breakpoint trap.
SIGURG    I                High bandwidth data is available at a socket.
SIGXCPU   A                CPU time limit exceeded.
SIGXFSZ   A                File size limit exceeded.

BusyBox init

BusyBox mặc định 1.29.2 reboot gửi một SIGTERM đến các quá trình, ngủ trong một giây và sau đó gửi SIGKILL. Đây dường như là một quy ước chung giữa các bản phân phối khác nhau.

Khi bạn tắt hệ thống BusyBox với:

reboot

nó gửi một tín hiệu đến quá trình init.

Sau đó, trình xử lý tín hiệu init kết thúc gọi:

static void run_shutdown_and_kill_processes(void)
{
    /* Run everything to be run at "shutdown".  This is done _prior_
     * to killing everything, in case people wish to use scripts to
     * shut things down gracefully... */
    run_actions(SHUTDOWN);

    message(L_CONSOLE | L_LOG, "The system is going down NOW!");

    /* Send signals to every process _except_ pid 1 */
    kill(-1, SIGTERM);
    message(L_CONSOLE, "Sent SIG%s to all processes", "TERM");
    sync();
    sleep(1);

    kill(-1, SIGKILL);
    message(L_CONSOLE, "Sent SIG%s to all processes", "KILL");
    sync();
    /*sleep(1); - callers take care about making a pause */
}

mà in ra thiết bị đầu cuối:

The system is going down NOW!
Sent SIGTERM to all processes
Sent SIGKILL to all processes

Đây là một ví dụ cụ thể tối thiểu về điều đó .

Các tín hiệu được gửi bởi hạt nhân


8

Sau khi tìm kiếm nhanh trên Google cho sigint và sigterm , có vẻ như sự khác biệt dự kiến ​​duy nhất giữa hai là liệu nó được bắt đầu bằng phím tắt hay bởi một lệnh gọi rõ ràng tới kill.

Kết quả là, bạn có thể, chẳng hạn, chặn dấu hiệu và làm điều gì đó đặc biệt với nó, biết rằng nó có thể được gửi bằng một phím tắt. Có lẽ làm mới màn hình hoặc một cái gì đó, thay vì chết (không được khuyến khích, như mọi người mong đợi ^Cđể giết chương trình, chỉ là một ví dụ).

Tôi cũng học được rằng ^\nên gửi sigquit, mà tôi có thể bắt đầu tự sử dụng. Trông rất hữu ích.


3

Sử dụng kill(cả lệnh gọi hệ thống và tiện ích`, bạn có thể gửi hầu hết mọi tín hiệu đến bất kỳ quá trình nào, nếu bạn đã được phép. Một quá trình không thể phân biệt cách một tín hiệu đi vào cuộc sống và ai đã gửi nó.

Điều đó đang được nói, SIGINT thực sự có nghĩa là để ngắt Ctrl-C, trong khi SIGTERM là tín hiệu đầu cuối chung. Không có khái niệm về tín hiệu là "mạnh hơn", với ngoại lệ duy nhất là có những tín hiệu không thể bị chặn hoặc xử lý (SIGKILL và SIGSTOP, theo trang người).

Một tín hiệu chỉ có thể "mạnh hơn" so với một tín hiệu khác về cách một quá trình nhận xử lý tín hiệu (và hành động mặc định cho tín hiệu đó là gì). Ví dụ, theo mặc định, cả SIGTERM và SIGINT đều dẫn đến kết thúc. Nhưng nếu bạn bỏ qua SIGTERM thì nó sẽ không kết thúc quá trình của bạn, trong khi SIGINT vẫn làm.


0

Ngoại trừ một số tín hiệu, bộ xử lý tín hiệu có thể bắt các tín hiệu khác nhau hoặc hành vi mặc định khi nhận được tín hiệu có thể được sửa đổi. Xem signal(7)trang người đàn ông để biết chi tiết.


Có, nhưng nếu tôi không biết "ý nghĩa" của một dấu đơn thì việc bắt được tín hiệu là vô nghĩa, vì tôi sẽ không biết phải làm gì trong ứng dụng của mình. GNU C ví dụ giải thích sự khác biệt giữa SIGQUIT và SIGTERM. Nhưng nó mang lại cho ít thông tin về SIGINT: gnu.org/s/libc/manual/html_node/Termination-Signals.html
Mecki

"Tín hiệu SIGINT(" ngắt chương trình ") được gửi khi người dùng nhập ký tự INTR (bình thường C-c)." "SIGINT 2 Thuật ngữ Ngắt từ bàn phím" Bạn nhấn Ctrl-C, SIGINTsẽ được gửi. Quá trình này thường chết. Thêm gì để cho?
Ignacio Vazquez-Abrams

Có khả năng có thể có một mô tả về ý định mà lập trình viên sẽ cho rằng người dùng sẽ có khi họ nhấn ctrl-c, tức là ngữ nghĩa của thông báo. Như một ví dụ, thông số HTTP nói rõ rằng khi người dùng gửi một yêu cầu GET, máy chủ không nên cho rằng họ muốn nó làm bất cứ điều gì ngoại trừ gửi lại phản hồi.
bdsl
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.