Когда процесс находится в пользовательском режиме, его можно прервать в любое время (переход в режим ядра). Когда ядро возвращается в пользовательский режим, он проверяет наличие ожидающих сигналов (включая те, которые используются для уничтожения процесса, такие как SIGTERM
и SIGKILL
). Это означает, что процесс может быть убит только при возврате в пользовательский режим.
Причина, по которой процесс не может быть убит в режиме ядра, заключается в том, что он может потенциально повредить структуры ядра, используемые всеми другими процессами на одной машине (так же, как уничтожение потока может привести к повреждению структур данных, используемых другими потоками в тот же процесс).
Когда ядро должно выполнить что-то, что может занять много времени (ожидание на трубке, написанном другим процессом или ожидающее, когда аппаратное обеспечение что-то сделает, например), он спит, отмечая себя как спящий и вызывающий планировщик для переключения на другой процесс (если нет процесса без сна, он переключается на «фиктивный» процесс, который сообщает процессору замедлить бит и сидит в цикле — цикл простоя).
Если сигнал отправляется в спящий режим, его необходимо разбудить, прежде чем он вернется в пространство пользователя и, таким образом, обработает ожидающий сигнал. Здесь у нас есть разница между двумя основными типами сна:
TASK_INTERRUPTIBLE
, прерывистый сон. Если задача отмечена этим флагом, она спит, но может быть разбужена сигналами. Это означает, что код, обозначающий задачу как спящий, ожидает возможного сигнала, и после того, как он просыпается, он проверит его и вернется с системного вызова. После обработки сигнала системный вызов может быть автоматически перезапущен (и я не буду вдаваться в подробности о том, как это работает).
TASK_UNINTERRUPTIBLE
, бесперебойный сон. Если задача отмечена этим флагом, она не ожидает, что ее разбудят что-либо, кроме того, что она ожидает, либо потому, что ее невозможно перезапустить, либо потому, что программы ожидают, что системный вызов будет атомарным. Это также можно использовать для сон, которые, как известно, очень короткие.
TASK_KILLABLE
(упоминается в статье LWN, связанной с ответом ddaa) - это новый вариант.
Это отвечает на ваш первый вопрос. Что касается вашего второго вопроса: вы не можете избежать бесцельных сна, это обычная вещь (это происходит, например, каждый раз, когда процесс читает/записывает с/на диск); однако они должны длиться всего лишь часть секунды. Если они длится намного дольше, обычно это означает аппаратную проблему (или проблему с драйвером устройства, которая аналогична ядру), когда драйвер устройства ожидает, что аппаратное обеспечение сделает что-то, чего никогда не произойдет. Это также означает, что вы используете NFS, а сервер NFS недоступен (он ждет восстановления сервера, вы также можете использовать опцию «intr», чтобы избежать проблемы).
И наконец, причина, по которой вы не можете восстановить, по той же причине, что ядро ждет, пока не вернется в пользовательский режим, чтобы доставить сигнал или убить процесс: это потенциально повредило бы структуры данных ядра (код, ожидающий прерывания сна, может получить ошибка, которая говорит ему вернуться в пространство пользователя, где процесс может быть убит, ожидающий в режиме бесперебойного сна ожидания код не ожидает никакой ошибки).
, пожалуйста, поделитесь этим кодом? – again 2018-02-20 09:29:29