Khi một quá trình ở chế độ người dùng, nó có thể bị gián đoạn bất cứ lúc nào (chuyển sang chế độ kernel). Khi kernel trở về chế độ người dùng, nó sẽ kiểm tra xem có bất kỳ tín hiệu nào đang chờ xử lý hay không (bao gồm cả những tín hiệu được sử dụng để giết tiến trình, chẳng hạn như SIGTERM
và SIGKILL
). Điều này có nghĩa là một quá trình chỉ có thể bị giết khi trở về chế độ người dùng.
Lý do một tiến trình không thể bị giết trong chế độ kernel là vì nó có khả năng làm hỏng các cấu trúc kernel được sử dụng bởi tất cả các tiến trình khác trong cùng một máy (cùng cách giết chết một luồng có thể làm hỏng cấu trúc dữ liệu được sử dụng bởi các luồng khác trong cùng tiến trình) .
Khi hạt nhân cần phải làm một việc gì đó có thể mất nhiều thời gian (chờ trên đường ống được viết bởi một quy trình khác hoặc chờ phần cứng làm gì đó), nó sẽ ngủ bằng cách đánh dấu là đang ngủ và gọi trình lập lịch để chuyển sang trình khác quá trình (nếu không có quá trình không ngủ, nó sẽ chuyển sang quá trình "giả" để bảo cpu làm chậm một chút và ngồi trong một vòng lặp - vòng lặp nhàn rỗi).
Nếu một tín hiệu được gửi đến một quá trình ngủ, nó phải được đánh thức trước khi nó trở lại không gian người dùng và do đó xử lý tín hiệu đang chờ xử lý. Ở đây chúng ta có sự khác biệt giữa hai loại giấc ngủ chính:
TASK_INTERRUPTIBLE
, giấc ngủ bị gián đoạn. Nếu một nhiệm vụ được đánh dấu bằng cờ này, nó đang ngủ, nhưng có thể bị đánh thức bởi các tín hiệu. Điều này có nghĩa là mã đánh dấu nhiệm vụ đang ngủ đang mong đợi một tín hiệu có thể và sau khi nó thức dậy sẽ kiểm tra nó và trả về từ cuộc gọi hệ thống. Sau khi tín hiệu được xử lý, cuộc gọi hệ thống có khả năng có thể được tự động khởi động lại (và tôi sẽ không đi vào chi tiết về cách thức hoạt động của nó).
TASK_UNINTERRUPTIBLE
, giấc ngủ không ngớt. Nếu một tác vụ được đánh dấu bằng cờ này, nó sẽ không bị đánh thức bởi bất cứ thứ gì khác ngoài bất cứ điều gì nó đang chờ đợi, bởi vì nó không thể dễ dàng được khởi động lại, hoặc bởi vì các chương trình đang mong đợi hệ thống gọi là nguyên tử. Điều này cũng có thể được sử dụng cho giấc ngủ được biết là rất ngắn.
TASK_KILLABLE
(được đề cập trong bài viết của LWN được liên kết với câu trả lời của ddaa) là một biến thể mới.
Điều này trả lời câu hỏi đầu tiên của bạn. Đối với câu hỏi thứ hai của bạn: bạn không thể tránh những giấc ngủ không bị gián đoạn, chúng là một điều bình thường (ví dụ, nó xảy ra mỗi khi một quá trình đọc / ghi từ / vào đĩa); tuy nhiên, chúng chỉ nên kéo dài một phần của giây. Nếu chúng tồn tại lâu hơn, điều đó thường có nghĩa là sự cố phần cứng (hoặc sự cố trình điều khiển thiết bị, trông giống với kernel), trong đó trình điều khiển thiết bị đang chờ phần cứng làm điều gì đó sẽ không bao giờ xảy ra. Điều đó cũng có nghĩa là bạn đang sử dụng NFS và máy chủ NFS không hoạt động (nó đang chờ máy chủ khôi phục; bạn cũng có thể sử dụng tùy chọn "xâm nhập" để tránh sự cố).
Cuối cùng, lý do bạn không thể khôi phục là lý do tương tự hạt nhân chờ cho đến khi trở về chế độ người dùng để phát tín hiệu hoặc giết quá trình: nó có khả năng làm hỏng cấu trúc dữ liệu của hạt nhân (mã chờ trong chế độ ngủ bị gián đoạn có thể nhận được lỗi cho biết để trở về không gian người dùng, nơi quá trình có thể bị giết, mã chờ trong một giấc ngủ không bị gián đoạn không mong đợi bất kỳ lỗi nào).
TASK_UNINTERUPTIBLE
trạng thái bất cứ khi nào hệ thống không ở trạng thái nhàn rỗi, do đó buộc phải thu thập dữ liệu, chờ truyền khi người dùng siêu thoát? Đây sẽ là một mỏ vàng để tin tặc lấy thông tin, trở về trạng thái zombie và truyền thông tin qua mạng khi không hoạt động. Một số người có thể lập luận rằng đây là một cách để tạo ra mộtBlackdoor
quyền hạn, để vào và thoát khỏi bất kỳ hệ thống nào theo ý muốn. Tôi tin tưởng rằng lỗ hổng này có thể được niêm phong vĩnh viễn, bằng cách loại bỏ `TASK_UNINTERUPTIB