Вопрос

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

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

Решение

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

Чтобы понять, что это значит, вам нужно разобраться в концепции прерываемого системного вызова.Классическим примером является 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) примерно переводится как "поток", который может иметь или не иметь отдельную запись "thread group" в / proc

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top