Всегда ли выполняется процесс инициализации UNIX?

У меня есть вопрос о том, как работает процесс инициализации в UNIX. Насколько я понимаю, первым запускается процесс инициализации, а затем от него ответвляются другие процессы.

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

Каков наилучший способ справиться с этой проблемой? Должен ли процесс инициализации просто всегда запускать бесконечный цикл, и нам не нужно беспокоиться о потраченных впустую ресурсах? Или есть лучший способ.

Любая помощь будет высоко оценена, Бен


person BenJacob    schedule 22.04.2016    source источник


Ответы (4)


Процесс 1 никогда не должен завершаться; многие (все?) реализации Unix вызовут сбой системы, если это произойдет.

Однако процесс 1 не должен делать что-то большее, чем это (я предполагаю, что ядро ​​​​открывает fds 0, 1 и 2 на консоли перед передачей управления пользовательскому пространству — проверьте документацию вашего ядра для этой и других деталей среды начальной загрузки, если вы на самом деле собираетесь написать init самостоятельно):

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>

int main(void)
{
    pid_t child = fork();
    if (child == -1) {
        perror("init: fork");
        return 1;
    }
    if (child == 0) {
        execl("/etc/rc", "/etc/rc", (char*)0);
        perror("/etc/rc");
        return 1;
    }
    for (;;)
        wait(0);
}

После запуска /etc/rc он действительно входит в бесконечный цикл, вызывая wait снова и снова и отбрасывая результаты. Но wait — это блокирующий системный вызов. Каждый раз, когда он вызывается, ядро ​​отбирает ЦП у процесса 1 и передает его процессу, который выполняет полезную работу; wait вернется только тогда, когда есть выходивший дочерний элемент, о котором нужно сообщить. (Если нет процессов с полезной работой, ЦП будет переведен в «спящий» режим с низким энергопотреблением до тех пор, пока какое-либо внешнее событие, например, человек не начнет печатать на клавиатуре или не прибудет сетевой пакет , дает работающему процессу некоторую работу.)

С этим минимальным init /etc/rc полностью отвечает за запуск всех программ, необходимых для того, чтобы компьютер делал что-то полезное, и эти программы несут ответственность за то, чтобы они продолжали работать столько, сколько необходимо; если случится так, что все процессы, кроме этого, завершатся, он просто заснет в wait навсегда. Более сложные реализации сделают больше, например. перезапуск сетевых серверов в случае их сбоя.

person zwol    schedule 28.02.2017

Для этого есть решение: SIGCHLD. Это сигнал, который может быть доставлен родителю, когда дочерний элемент меняет свой статус (останавливается или выходит). Таким образом, родитель может перейти в спящий режим (например, sigpause, sigsuspend) и будет прерван, когда дочерний процесс завершится, тогда родитель запустит соответствующий обработчик сигнала для вызова одной из функций семейства wait.

person Jean-Baptiste Yunès    schedule 23.04.2016
comment
Итак, прав ли я, думая, что системный вызов wait возобновляет родительский процесс только после завершения дочернего процесса, а сигнал SIGCHILD отличается от механизма wait? - person BenJacob; 25.04.2016
comment
wait используется для: получения статуса завершения завершенного дочернего процесса и удаления дочернего процесса из списка процессов (без зомби). wait ничего не возобновляет. wait может синхронно ожидать завершения дочернего процесса, SIGCHILD — это асинхронное событие, предупреждающее о завершении дочернего процесса. - person Jean-Baptiste Yunès; 25.04.2016

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

Я никогда не видел процесса, написанного для приема стандартного ввода во время процесса загрузки, хотя это возможно, если вы хотите его написать. Я знаю, что сценарии инициализации могут быть написаны с зависимостями, в зависимости от того, какой дистрибутив вы используете и каков процесс загрузки (upstart, system V init и т. д.). Но по умолчанию они запускаются синхронно в порядке, который использует инициализация. Я не уверен, как блокирование этого процесса синхронизации... ожидание ввода повлияет на систему. Скорее всего, он бы сделал именно это... остановился и дождался ввода, прежде чем продолжить.

person dman    schedule 22.04.2016

Процесс инициализации действительно выполняет бесконечный цикл, но он не использует каких-либо значительных ресурсов, поскольку он управляется прерыванием. Он просто ждет, пока процессы умрут или ему будут отправлены другие сигналы. Во время интервалов ожидания init использует нулевые циклы ЦП.

person jlliagre    schedule 22.04.2016