Что такое непрерывный процесс?


Иногда, когда я пишу программу в Linux, и она выходит из строя из-за какой-то ошибки, она становится непрерывным процессом и продолжает работать вечно, пока я не перезагрузлю компьютер (даже если я выхожу из системы). Мои вопросы таковы:

  • , Что вызывает процесс, чтобы стать бесперебойного?
  • Как мне предотвратить это?
  • Это, вероятно, глупый вопрос, но есть ли способ прервать его без перезагрузки моего компьютера?
6 131

6 ответов:

Непрерывный процесс-это процесс, находящийся в системном вызове (функция ядра), который не может быть прерван сигналом.

Чтобы понять, что это означает, вам нужно понять концепцию прерываемого системного вызова. Классический пример - read(). Это системный вызов, который может занять много времени (секунд), так как он потенциально может включать в себя вращение жесткого диска или перемещение головок. В течение большей части этого времени процесс будет спать, блокируя аппаратура.

Пока процесс спит в системном вызове, он может получить асинхронный сигнал unix (скажем, SIGTERM), тогда происходит следующее:

    Системные вызовы завершаются преждевременно и настраиваются на возврат-EINTR в пользовательское пространство.
  • обработчик сигнала выполняется.
  • если процесс все еще выполняется, он получает возвращаемое значение из системного вызова и может выполнить тот же вызов снова.

Раннее возвращение из системного вызова позволяет пользователю космический код, чтобы немедленно изменить свое поведение в ответ на сигнал. Например, окончание чисто в реакции на SIGINT или SIGTERM.

С другой стороны, некоторые системные вызовы не могут быть прерваны таким образом. Если система по какой-то причине вызывает остановку, процесс может бесконечно оставаться в этом неубиваемом состоянии.

LWN опубликовал хорошую статью, которая затронула эту тему в июле.

Чтобы ответить на первоначальный вопрос:

  • Как это сделать предотвратите это: выясните, какой драйвер вызывает у вас проблемы, и либо прекратите использовать, либо станьте хакером ядра и исправьте это.

  • Как убить бесперебойный процесс без перезагрузки: каким-то образом заставить системный вызов завершиться. Часто наиболее эффективным способом сделать это, не нажимая на выключатель питания, является потянуть за шнур питания. Вы также можете стать хакером ядра и заставить драйвер использовать TASK_KILLABLE, как описано в статье LWN.

Когда процесс находится в пользовательском режиме, он может быть прерван в любое время (переход в режим ядра). Когда ядро возвращается в пользовательский режим, оно проверяет, есть ли какие-либо ожидающие сигналы (в том числе те, которые используются для уничтожения процесса, такие как SIGTERM и SIGKILL). Это означает, что процесс может быть убит только при возвращении в пользовательский режим.

Причина, по которой процесс не может быть убит в режиме ядра, заключается в том, что он потенциально может повредить структуры ядра, используемые всеми другими процессами в том же режиме. машина (таким же образом убийство потока может потенциально повредить структуры данных, используемые другими потоками в том же процессе).

Когда ядру нужно сделать что-то, что может занять много времени (например, ожидание на канале, написанном другим процессом, или ожидание аппаратного обеспечения, чтобы сделать что-то), оно спит, помечая себя как спящий и вызывая планировщик для переключения на другой процесс (если нет не спящего процесса, он переключается на "фиктивный" процесс, который сообщает процессору, что он должен работать). притормозите немного и садитесь в петлю-петлю холостого хода).

Если сигнал передается спящему процессу, он должен быть разбужен, прежде чем он вернется в пользовательское пространство и, таким образом, обработает ожидающий сигнал. Здесь мы имеем различие между двумя основными типами сна:

  • TASK_INTERRUPTIBLE, прерываемый сон. Если задача помечена этим флажком, она спит, но может быть разбужена сигналами. Это означает, что код, обозначивший задачу как спящую, ожидает возможного сигнала и после него проснется будет проверять это и возвращение из системного вызова. После обработки сигнала системный вызов потенциально может быть автоматически перезапущен (и я не буду вдаваться в подробности о том, как это работает).
  • TASK_UNINTERRUPTIBLE, непрерывный сон. Если задача помечена этим флагом, она не ожидает, что ее разбудит что-то другое, кроме того, что она ожидает, либо потому, что она не может быть легко перезапущена, либо потому, что программы ожидают, что системный вызов будет атомарным. Это также можно использовать ибо сны, как известно, очень короткие.

TASK_KILLABLE (упомянутый в статье LWN, связанной с ответом ddaa) - это новый вариант.

Это ответ на ваш первый вопрос. Что касается вашего второго вопроса: Вы не можете избежать бесперебойного сна, это нормальная вещь (это происходит, например, каждый раз, когда процесс читает/записывает с/на диск); однако они должны длиться только долю секунды. Если они длятся намного дольше, это обычно означает аппаратную проблему (или проблему драйвера устройства, который выглядит так же для ядра), где драйвер устройства ждет, чтобы аппаратное обеспечение сделало что-то, что никогда не произойдет. Это также может означать, что вы используете NFS и сервер NFS не работает (он ждет восстановления сервера; вы также можете использовать опцию "intr", чтобы избежать проблемы).

Наконец, причина, по которой вы не можете восстановить, та же самая, по которой ядро ждет возвращения в пользовательский режим, чтобы передать сигнал или убить процесс: это потенциально повредит данные ядра структуры (код, ожидающий прерываемого сна, может получить ошибку, которая говорит ему вернуться в пространство пользователя, где процесс может быть убит; код, ожидающий бесперебойного сна, не ожидает никакой ошибки).

Бесперебойные процессы обычно ожидают ввода-вывода после сбоя страницы.

Рассмотрим это:

  • поток пытается получить доступ к странице, которая не находится в ядре (либо исполняемый файл, который загружен по требованию, страница анонимной памяти, которая была заменена, или файл mmap()'d, который загружен по требованию, что во многом одно и то же)
  • ядро теперь (пытается) загрузить его в
  • процесс не может продолжаться, пока страница не будет доступна.

Процесс/задача не может быть прерван в этом состоянии, потому что он не может обрабатывать никакие сигналы; если бы это произошло, произошла бы другая ошибка страницы, и она вернулась бы туда, где была.

Когда я говорю "процесс", я действительно имею в виду "задачу", которая в Linux (2.6) грубо переводится как "поток", который может иметь или не иметь отдельную запись "группа потоков" в /proc

В некоторых случаях он может ждать очень долго. Типичным примером этого может быть ситуация, когда исполняемый файл или файл mmap находится в сети файловая система, в которой произошел сбой сервера. Если ввод-вывод в конечном итоге завершится успешно, задача будет продолжена. Если это в конечном итоге не удастся, задача, как правило, получит SIGBUS или что-то в этом роде.

Возможно ли, что программа может быть написана для инициирования процесса, который переходит в состояние TASK_UNINTERUPTIBLE всякий раз, когда система не находится в состоянии ожидания, тем самым принудительно собирая данные, ожидая передачи после выхода суперпользователя? Это была бы золотая жила для хакеров, чтобы получить информацию, вернуться в состояние зомби и передавать информацию через сеть на холостом ходу. Некоторые могут возразить, что это один из способов создать Blackdoor для сильных мира сего, чтобы входить и выходить из любой системы по своему желанию. Я твердо верю, что эту лазейку можно закрыть навсегда, устранив состояние TASK_UNINTERUPTIBLE.

Я рассматриваю это как серьезную, но тонкую проблему безопасности для систем Linux, которые имеют репутацию безопасности, благодаря наделению полномочиями суперпользователя. Я работаю над тем, чтобы стать хакером ядра, однако, я думаю, что есть хакеры ядра, которые могут исправить это фиаско.

К вашему 3-му вопросу: Я думаю, что вы можете убить бесперебойные процессы, запустив sudo kill -HUP 1. Он перезапустит init без завершения запущенных процессов, и после его запуска мои бесперебойные процессы исчезли.

Если вы говорите о процессе" зомби "(который обозначается как" зомби " в выводе ps), то это безвредная запись в списке процессов, ожидающая, пока кто-то соберет ее код возврата, и ее можно было бы безопасно игнорировать.

Не могли бы вы описать, что такое "непрерывный процесс" для вас? Переживает ли он "убийство-9"и счастливо пыхтит? Если это так, то он застрял на каком-то syscall, который застрял в каком-то драйвере, и вы застряли с этим процессом до тех пор, пока перезагрузка (а иногда лучше перезагрузить в ближайшее время) или выгрузка соответствующего драйвера (что вряд ли произойдет). Вы можете попробовать использовать "strace", чтобы узнать, где застрял ваш процесс, и избежать его в будущем.