Điều gì gây ra các tín hiệu khác nhau được gửi?


28

Đôi khi tôi có một chút bối rối bởi tất cả các tín hiệu mà một quá trình có thể nhận được. Theo tôi hiểu, một quy trình có một trình xử lý mặc định ( bố trí tín hiệu ) cho mỗi tín hiệu này, nhưng nó có thể cung cấp trình xử lý riêng bằng cách gọi sigaction().

Vì vậy, đây là câu hỏi của tôi: điều gì gây ra mỗi tín hiệu được gửi? Tôi nhận ra rằng bạn có thể gửi tín hiệu theo cách thủ công đến các quy trình đang chạy thông qua -stham số kill, nhưng hoàn cảnh tự nhiên mà các tín hiệu này được gửi là gì? Ví dụ, khi nào SIGINTđược gửi?

Ngoài ra, có bất kỳ hạn chế về tín hiệu nào có thể được xử lý? Các SIGSEGVtín hiệu thậm chí có thể được xử lý và kiểm soát trở lại ứng dụng?


Một câu trả lời thích hợp cho vấn đề này sẽ trở nên tuyệt vời, và về cơ bản sao chép thông tin trong bài viết trên Wikipedia về vấn đề này, vì vậy tôi sẽ chỉ vào đó.
Shawn J. Goff

@Shawn: Bài viết Wikipedia có một danh sách các tín hiệu, nhưng không có sự trình bày rõ ràng về việc ai sẽ gửi những tín hiệu nào.
Gilles 'SO- ngừng trở nên xấu xa'

Câu trả lời:


41

Ngoài các quá trình gọi kill(2), một số tín hiệu được gửi bởi kernel (hoặc đôi khi bởi chính quá trình) trong các trường hợp khác nhau:

  • Trình điều khiển thiết bị đầu cuối gửi tín hiệu tương ứng với các sự kiện khác nhau:
    • Thông báo báo chí chính: SIGINT(vui lòng quay lại vòng lặp chính) trên Ctrl+ C, SIGQUIT(vui lòng thoát ngay lập tức) trên Ctrl+ \, SIGTSTP(vui lòng tạm dừng) trên Ctrl+ Z. Các phím có thể được thay đổi bằng sttylệnh.
    • SIGTTINSIGTTOUđược gửi khi một quá trình nền cố gắng đọc hoặc ghi vào thiết bị đầu cuối kiểm soát của nó.
    • SIGWINCH được gửi để báo hiệu rằng kích thước của cửa sổ đầu cuối đã thay đổi.
    • SIGHUPđược gửi đến dấu hiệu cho thấy thiết bị đầu cuối đã biến mất (về mặt lịch sử vì modem của bạn có h ung lên , ngày nay thường vì bạn đã đóng cửa sổ giả lập thiết bị đầu cuối).
  • Một số bẫy bộ xử lý có thể tạo ra tín hiệu. Các chi tiết là kiến ​​trúc và hệ thống phụ thuộc; đây là những ví dụ điển hình:
    • SIGBUS cho một bộ nhớ truy cập không được phân bổ;
    • SIGSEGV để truy cập vào một trang chưa được ánh xạ;
    • SIGILL cho một hướng dẫn bất hợp pháp (opcode xấu);
    • SIGFPEcho một lệnh dấu phẩy động với các đối số xấu (ví dụ sqrt(-1)).
  • Một số tín hiệu thông báo cho quá trình đích mà một số sự kiện hệ thống đã xảy ra:
    • SIGALRMthông báo rằng bộ hẹn giờ được thiết lập bởi quá trình đã hết hạn. Bộ hẹn giờ có thể được thiết lập với alarm, setitimervà những người khác.
    • SIGCHLD thông báo về một quá trình mà một trong những đứa con của nó đã chết.
    • SIGPIPEđược tạo khi một quá trình cố gắng ghi vào một đường ống khi kết thúc đọc đã bị đóng (ý tưởng là nếu bạn chạy foo | barbarthoát, foobị giết bởi a SIGPIPE).
    • SIGPOLL(còn được gọi SIGIO) thông báo cho quá trình mà một sự kiện có thể gây ô nhiễm đã xảy ra. POSIX chỉ định các sự kiện có thể gây ô nhiễm được đăng ký thông qua I_SETSIG ioctl. Nhiều hệ thống cho phép các sự kiện có thể bỏ phiếu trên bất kỳ mô tả tệp nào, được đặt qua O_ASYNC fcntlcờ. Một tín hiệu liên quan là SIGURG, thông báo về dữ liệu khẩn cấp trên thiết bị (được đăng ký qua I_SETSIG ioctl) hoặc ổ cắm .
    • Trên một số hệ thống, SIGPWRđược gửi đến tất cả các quy trình khi UPS báo hiệu sắp xảy ra sự cố mất điện.

Những danh sách này không đầy đủ. Tín hiệu tiêu chuẩn được xác định trong signal.h.

Hầu hết các tín hiệu có thể bị bắt và xử lý (hoặc bỏ qua) bởi ứng dụng. Hai tín hiệu di động duy nhất không thể bắt được là SIGKILL(chỉ chết) và STOP(dừng thực thi).

SIGSEGV( lỗi phân khúc ) và anh em họ SIGBUS( lỗi xe buýt ) có thể bị bắt, nhưng đó là một ý tưởng tồi trừ khi bạn thực sự biết bạn đang làm gì. Một ứng dụng phổ biến để bắt chúng là in dấu vết ngăn xếp hoặc thông tin gỡ lỗi khác. Một ứng dụng nâng cao hơn là triển khai một số loại quản lý bộ nhớ trong quá trình hoặc để bẫy các hướng dẫn xấu trong các công cụ máy ảo.

Cuối cùng, hãy để tôi đề cập đến một cái gì đó không phải là một tín hiệu. Khi bạn nhấn Ctrl+ Dở đầu một dòng trong chương trình đọc đầu vào từ thiết bị đầu cuối, điều này sẽ cho chương trình biết rằng đã kết thúc tập tin đầu vào. Đây không phải là tín hiệu: nó được truyền qua API đầu vào / đầu ra. Giống như Ctrl+ Cvà bạn bè, khóa có thể được cấu hình stty.


Và SIGHUP, modem của bạn đã gác máy. :-)
Keith

1
Một điều khác cần lưu ý SIGFPE:, hơi vô tình, cũng được báo hiệu trên số nguyên chia cho 0 và đôi khi trên tràn số nguyên đã ký.
ephemient

18

Để trả lời câu hỏi thứ hai của bạn trước: SIGSTOPSIGKILLứng dụng không thể bị bắt, nhưng mọi tín hiệu khác đều có thể, thậm chí SIGSEGV. Thuộc tính này hữu ích cho việc gỡ lỗi - ví dụ, với sự hỗ trợ của thư viện phù hợp, bạn có thể lắng nghe SIGSEGVvà tạo một backtrace ngăn xếp để hiển thị nơi xảy ra lỗi segfault đó.

Từ chính thức (đối với Linux, dù sao) về những gì từng tín hiệu có sẵn bằng cách nhập man 7 signaltừ một dòng lệnh Linux. http://linux.die.net/man/7/signal có cùng thông tin, nhưng các bảng khó đọc hơn.

Tuy nhiên, không có một số kinh nghiệm về tín hiệu, thật khó để biết từ những mô tả ngắn về những gì họ làm trong thực tế, vì vậy đây là cách giải thích của tôi:

Kích hoạt từ bàn phím

  • SIGINTxảy ra khi bạn nhấn CTRL+C.
  • SIGQUITđược kích hoạt bởi CTRL+\, và bãi bỏ lõi.
  • SIGTSTPđình chỉ chương trình của bạn khi bạn nhấn CTRL+Z. Không giống như SIGSTOP, nó có thể bắt được, điều này mang lại cho các chương trình như vicơ hội đặt lại thiết bị đầu cuối về trạng thái an toàn trước khi tạm dừng.

Tương tác đầu cuối

  • SIGHUP ("Hangup") là những gì xảy ra khi bạn đóng xterm của bạn (hoặc nếu không thì ngắt kết nối thiết bị đầu cuối) trong khi chương trình của bạn đang chạy.
  • SIGTTINSIGTTOUtạm dừng chương trình của bạn nếu nó cố đọc hoặc ghi vào thiết bị đầu cuối trong khi nó đang chạy ẩn. Để SIGTTOUxảy ra, tôi nghĩ rằng chương trình cần phải được viết /dev/tty, không chỉ là thiết bị xuất chuẩn mặc định.

Kích hoạt bởi một ngoại lệ CPU

Điều này có nghĩa là chương trình của bạn đã cố gắng làm điều gì đó sai.

  • SIGILLcó nghĩa là một hướng dẫn bộ xử lý bất hợp pháp hoặc không xác định. Điều này có thể xảy ra nếu bạn cố truy cập trực tiếp vào cổng I / O của bộ xử lý.
  • SIGFPEcó nghĩa là đã có một lỗi toán học phần cứng; rất có thể chương trình đã cố gắng chia cho số không.
  • SIGSEGV có nghĩa là chương trình của bạn đã cố gắng truy cập vào một vùng bộ nhớ chưa được khai thác.
  • SIGBUScó nghĩa là chương trình truy cập bộ nhớ không chính xác theo một cách khác; Tôi sẽ không đi vào chi tiết cho bản tóm tắt này.

Quá trình tương tác

  • SIGPIPExảy ra nếu bạn cố gắng ghi vào một đường ống sau khi đầu đọc của ống đóng lại. Xem man 7 pipe.
  • SIGCHLDxảy ra khi một tiến trình con bạn tạo hoặc thoát hoặc bị đình chỉ (bởi SIGSTOPhoặc tương tự).

Hữu ích cho việc tự báo hiệu

  • SIGABRTthường được gây ra bởi chương trình gọi abort()hàm và gây ra kết xuất lõi theo mặc định. Sắp xếp một "nút hoảng loạn".
  • SIGALRMđược gây ra bởi lệnh alarm()gọi hệ thống, điều này sẽ khiến kernel phân phối a SIGALRMđến chương trình sau một số giây được chỉ định. Xem man 2 alarmman 2 sleep.
  • SIGUSR1SIGUSR2được sử dụng tuy nhiên chương trình thích. Chúng có thể hữu ích cho tín hiệu giữa các quá trình.

Gửi bởi quản trị viên

Các tín hiệu này thường được gửi từ dấu nhắc lệnh, thông qua killlệnh fghoặc bgtrong trường hợp SIGCONT.

  • SIGKILLSIGSTOPlà những tín hiệu không thể chặn được. Việc đầu tiên luôn chấm dứt quá trình ngay lập tức; thứ hai đình chỉ quá trình.
  • SIGCONT nối lại một quá trình bị đình chỉ.
  • SIGTERMlà một phiên bản có thể bắt được của SIGKILL.

Tín hiệu nào được gửi khi shutdownlệnh được sử dụng?
Nathan Osman

Điều đó phụ thuộc vào các kịch bản tắt máy. Thông thường, SIGTERMđược gửi đầu tiên, theo sau là một sự chậm trễ, tiếp theo là SIGKILL. Về nguyên tắc, đối với việc tắt máy ngay lập tức, cứng, kernel hoàn toàn không cần gửi tín hiệu; nó chỉ có thể ngừng chạy quá trình.
Jander
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.