`EINTR`: có một lý do đằng sau nó?


10

Nói nhỏ làm nền

EINTRlà lỗi mà cái gọi là các cuộc gọi hệ thống ngắt có thể quay trở lại. Nếu tín hiệu xảy ra trong khi cuộc gọi hệ thống đang chạy, tín hiệu đó không bị bỏ qua và trình xử lý tín hiệu được xác định cho nó mà SA_RESTARTkhông được đặt và trình xử lý này xử lý tín hiệu đó, thì cuộc gọi hệ thống sẽ trả về EINTRmã lỗi.

Là một lưu ý phụ, tôi đã gặp lỗi này rất thường xuyên sử dụng ncursestrong Python.

Câu hỏi

Có một lý do đằng sau hành vi này được quy định bởi tiêu chuẩn POSIX không? Người ta có thể hiểu rằng có thể không thể tiếp tục (tùy thuộc vào thiết kế kernel), tuy nhiên, lý do nào để không tự động khởi động lại ở cấp độ kernel? Đây là vì lý do di sản hoặc kỹ thuật? Nếu điều này là vì lý do kỹ thuật, những lý do này vẫn còn hiệu lực ngày nay? Nếu điều này là vì lý do di sản, thì lịch sử là gì?

Câu trả lời:


13

Thật khó để làm những việc không cần thiết trong một bộ xử lý tín hiệu, vì phần còn lại của chương trình ở trạng thái không xác định. Hầu hết các trình xử lý tín hiệu chỉ đặt một cờ, sau đó được kiểm tra và xử lý ở nơi khác trong chương trình.

Lý do không tự động khởi động lại cuộc gọi hệ thống:

Hãy tưởng tượng một ứng dụng nhận dữ liệu từ một ổ cắm bằng cách gọi và chặn recv() hệ thống liên tục . Trong kịch bản của chúng tôi, dữ liệu đến rất chậm và chương trình tồn tại lâu trong cuộc gọi hệ thống đó. Chương trình đó có bộ xử lý tín hiệu để SIGINTđặt cờ (được đánh giá ở nơi khác) và SA_RESTARTđược đặt để cuộc gọi hệ thống tự động khởi động lại. Hãy tưởng tượng rằng chương trình đang recv()chờ dữ liệu. Nhưng không có dữ liệu đến. Các khối gọi hệ thống. Chương trình bây giờ bắt ctrl- ctừ người dùng. Cuộc gọi hệ thống bị gián đoạn và trình xử lý tín hiệu, chỉ đặt cờ được thực thi. Sau đó recv()được khởi động lại, vẫn chờ dữ liệu. Vòng lặp sự kiện bị kẹt trong recv()và không có cơ hội để đánh giá cờ và thoát khỏi chương trình một cách duyên dáng.

Với SA_RESTARTkhông được thiết lập:

Trong trường hợp trên, khi SA_RESTARTkhông được đặt, recv()sẽ nhận được EINTRthay vì được khởi động lại. Các cuộc gọi hệ thống thoát và do đó có thể tiếp tục. Dĩ nhiên, chương trình nên (càng sớm càng tốt) kiểm tra cờ (được đặt bởi bộ xử lý tín hiệu) và làm sạch hoặc bất cứ điều gì nó làm.


Một quan điểm khác có thể đáng được thêm vào: skarnet.org/software/skalibs/libstddjb/safewrappers.html . Cuối cùng nó cũng nói như vậy (mặc dù rõ ràng hơn), ngoại trừ trong câu trả lời của bạn, bạn cho rằng thậm chí có thể không có thời gian nào cả.
Hibou57

2
Ngay cả với SA_RESTARTthiết lập, không phải tất cả các cuộc gọi hệ thống được tự động khởi động lại. Ví dụ: Linux không khởi động lại msgsnd()hoặc msgrcv().
Andrew Henle

5

Richard Gabriel đã viết một bài báo Sự trỗi dậy của 'Tệ hơn là tốt hơn' trong đó thảo luận về sự lựa chọn thiết kế ở đây trong Unix:

Hai người nổi tiếng, một người từ MIT và một người khác từ Berkeley (nhưng làm việc trên Unix) đã từng gặp nhau để thảo luận về các vấn đề hệ điều hành. Người đến từ MIT đã am hiểu về ITS (hệ điều hành MIT AI Lab) và đã đọc các nguồn Unix. Ông quan tâm đến cách Unix giải quyết vấn đề kẻ thua cuộc trên PC. Sự cố mất máy tính xảy ra khi chương trình người dùng gọi một thói quen hệ thống để thực hiện một thao tác dài có thể có trạng thái quan trọng, chẳng hạn như bộ đệm IO. Nếu một ngắt xảy ra trong quá trình hoạt động, trạng thái của chương trình người dùng phải được lưu. Bởi vì việc gọi thường trình hệ thống thường là một lệnh đơn, PC của chương trình người dùng không nắm bắt được trạng thái của quá trình. Thói quen hệ thống phải lùi ra hoặc nhấn về phía trước. Điều đúng đắn là sao lưu và khôi phục PC chương trình người dùng theo hướng dẫn đã gọi thói quen hệ thống để nối lại chương trình người dùng sau khi ngắt, ví dụ, nhập lại thói quen hệ thống. Nó được gọi làPC loser-ingbởi vì PC đang bị ép buộc loser mode, trong đó 'kẻ thua cuộc' là tên trìu mến của 'người dùng' tại MIT.

Anh chàng MIT đã không thấy bất kỳ mã nào xử lý trường hợp này và hỏi anh chàng New Jersey rằng vấn đề được xử lý như thế nào. Anh chàng người New Jersey nói rằng những người Unix đã nhận thức được vấn đề, nhưng giải pháp là để thói quen hệ thống luôn luôn kết thúc, nhưng đôi khi một mã lỗi sẽ được trả về, báo hiệu rằng thói quen hệ thống đã không hoàn thành hành động của nó. Sau đó, một chương trình người dùng chính xác phải kiểm tra mã lỗi để xác định xem có nên thử lại hệ thống thường xuyên hay không. Anh chàng MIT không thích giải pháp này vì đó không phải là điều đúng đắn.

Anh chàng người New Jersey nói rằng giải pháp Unix là đúng bởi vì triết lý thiết kế của Unix là sự đơn giản và điều đúng đắn là quá phức tạp. Bên cạnh đó, các lập trình viên có thể dễ dàng chèn bài kiểm tra và vòng lặp bổ sung này. Anh chàng MIT chỉ ra rằng việc thực hiện rất đơn giản nhưng giao diện với chức năng thì phức tạp. Anh chàng người New Jersey nói rằng sự đánh đổi đúng đắn đã được chọn trong Unix - cụ thể là, sự đơn giản trong triển khai quan trọng hơn sự đơn giản về giao diện.


1
Hai người nổi tiếng bước vào một quán bar - một từ MIT, một từ Berkeley và một từ New Jersey. Huh? Tôi nhận ra rằng đó là một trích dẫn, nhưng bạn có thể làm rõ nó? Đoạn cuối cũng hơi lộn xộn - giải pháp Unix đã đúng vì điều đúng quá phức tạp đối với Unix và vì vậy họ đã không thực hiện nó.
G-Man nói 'Phục hồi Monica'

Sản phẩm khả thi tối thiểu là một khái niệm liên quan. Giải pháp unix để sử dụng EINTR là khả thi và mang lại sự đơn giản trong cơ sở mã hệ điều hành có tính di động cao. Được ủy quyền cho mã người dùng, xử lý EINTR rất dễ dàng (chỉ cần thử lại), nhưng vẫn khó chịu.
Brad Schoening
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.