Когда процесс находится в режиме пользователя, он может быть прерван в любое время (переключение в режим ядра). Когда ядро возвращается в пользовательский режим, оно проверяет, есть ли какие-либо ожидающие сигналы (включая те, которые используются для остановки процесса, такие как SIGTERM
и SIGKILL
). Это означает, что процесс может быть остановлен только при возврате в режим пользователя.
Причина, по которой процесс не может быть уничтожен в режиме ядра, заключается в том, что он потенциально может повредить структуры ядра, используемые всеми другими процессами на той же машине (точно так же, как уничтожение потока может потенциально повредить структуры данных, используемые другими потоками в том же процессе) ,
Когда ядру необходимо выполнить что-то, что может занять много времени (например, в ожидании канала, написанного другим процессом или в ожидании аппаратного обеспечения что-либо сделать), оно спит, помечая себя как спящего и вызывая планировщик для переключения на другое процесс (если нет не спящего процесса, он переключается на «фиктивный» процесс, который указывает процессору немного замедляться и сидит в цикле - в цикле простоя).
Если сигнал отправляется в спящий процесс, его необходимо разбудить, прежде чем он вернется в пользовательское пространство и обработает ожидающий сигнал. Здесь у нас есть разница между двумя основными типами сна:
TASK_INTERRUPTIBLE
Прерванный сон. Если задание помечено этим флагом, оно спит, но может быть разбужено сигналами. Это означает, что код, пометивший задачу как спящий, ожидает возможного сигнала, а после его запуска проверит его и вернется из системного вызова. После обработки сигнала системный вызов может быть автоматически перезапущен (и я не буду вдаваться в подробности о том, как это работает).
TASK_UNINTERRUPTIBLE
Непрерывный сон. Если задача помечена этим флагом, она не ожидает, что ее разбудит что-либо, кроме того, что она ожидает, либо потому, что ее нелегко перезапустить, либо потому, что программы ожидают, что системный вызов будет атомарным. Это может также использоваться для снов, которые, как известно, очень короткие.
TASK_KILLABLE
(упоминается в статье LWN, на которую ссылается ответ ddaa) - это новый вариант.
Это отвечает на ваш первый вопрос. Что касается вашего второго вопроса: вы не можете избежать непрерывных снов, они нормальные (это происходит, например, каждый раз, когда процесс читает / пишет с / на диск); тем не менее, они должны длиться лишь доли секунды. Если они длятся намного дольше, это обычно означает проблему с оборудованием (или проблему с драйвером устройства, которая выглядит так же для ядра), когда драйвер устройства ждет, пока оборудование сделает что-то, что никогда не произойдет. Это также может означать, что вы используете NFS, а сервер NFS не работает (он ожидает восстановления сервера; вы также можете использовать опцию «intr», чтобы избежать проблемы).
Наконец, причина, по которой вы не можете восстановить, - это та же причина, по которой ядро ожидает возврата в режим пользователя, чтобы доставить сигнал или убить процесс: это может привести к повреждению структур данных ядра (код, ожидающий прерывистого сна, может получить ошибку, сообщающую ему вернуться в пользовательское пространство, где процесс может быть убит; код, ожидающий непрерывного сна, не ожидает ошибки).
TASK_UNINTERUPTIBLE
состояние, когда система не находится в состоянии ожидания, тем самым принудительно собирая данные, ожидая передачи после выхода суперпользователя? Это было бы золотой жилой для хакеров, чтобы получать информацию, возвращаться в состояние зомби и передавать информацию по сети в режиме ожидания. Некоторые могут утверждать, что это один из способов создатьBlackdoor
для сил, которые могут входить и выходить из любой системы по желанию. Я твердо верю, что эту лазейку можно закрыть навсегда, исключив `TASK_UNINTERUPTIB