Ядро Linux в комментариях

       

и надлежит очень общей функции,


Как и надлежит очень общей функции, sys_wait4 имеет множество параметров, некоторые из которых необязательны, pid, как всегда, представляет PID целевого процесса; нулевое и отрицательные значения имеют специальный смысл, как будет вскоре показано. stat_addr если его значением является не NULL, представляет адрес, в который должно быть скопировано состояние выхода прерванного дочернего процесса, options — это набор флагов, которые могут изменить поведение функции sys_wait4. ru, если его значением является не NULL, — это адрес, в который должна быть скопирована информация об использовании ресурсов прерванного дочернего процесса.

Если ей переданы любые недопустимые параметры, sys_wait4 возвращает код ошибки. Это решение кажется несколько грубым; вполне можно было бы просто игнорировать не имеющие важного значения флаги. Аргументы за выполнение этой задачи именно таким образом естественно заключаются в том, что если вызывающий процесс включает разряды, которые не собирался включать, он может столкнуться с неожиданным для себя поведением — в любом случае это означает, что вызывающий процесс ошибся и в этом случае лучше сообщить об ошибке, чем молча проигнорировать ошибку вызывающего процесса.

Выполняет цикл по всем непосредственным дочерним процессам данного процесса (но не по внучатым процессам и т.д.). Как упоминалось ранее в этой главе, самый младший (наиболее недавно созданный) дочерний процесс доступен посредством члена p_cptr структуры struct task_struct, а список более старших братьев этого самого младшего дочернего процесса — посредством его члена p_osptr; таким образом, функция sys_wait4 проходит по всем дочерним процессам родительского процесса, начиная с самого младшего дочернего процесса, циклически переходя к все более старшим его братьям.

Отфильтровывает неподходящие PID, исходя из значения аргумента pid. Обратите внимание, как будет обрабатываться аргумент pid равный –1 который позволяет выбрать любой процесс: значение этого pid не пройдет тесты в строках , и , поэтому он никогда не будет отклонен. Следовательно, это приводит к тому, что будет рассматриваться каждый дочерний процесс.



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

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

Отправляет retval идентификатору PID завершившегося дочернего процесса, подлежащего удалению. Это конец; retval больше не будет меняться.

Если текущий родительский процесс завершившегося процесса не является его исходным родительским процессом, процесс удаляет себя из текущей позиции в графе процессов (посредством REMOVE_LINKS, строка ), переустанавливает себя под исходным родительским процессом (посредством SET_LINKS, строка ), а затем отправляет своему родительскому процессу сигнал SIGCHLD, чтобы родительский процесс знал о выходе его дочернего процесса. Уведомление доставляется посредством notify_parent, описанной в (строка ).

Иначе — в обычном случае — может быть наконец вызвана функция release (строка ) для освобождения структуры struct task_struct завершившегося дочернего процесса. (Функция release будет рассмотрена через несколько минут, по завершении рассмотрения sys_wait4.)

Теперь дочерний процесс успешно завершен, поэтому функции sys_wait4 остается только вернуть успех; она переходит к строке , где возвращает значение retval (PID завершившегося дочернего процесса).

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



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

Если значение flag ненулевое, во время цикла for была достигнута строка , а значит по меньшей мере один дочерний процесс совпал с переданным аргументом pid — он просто не был зомби или остановленным, и поэтому не мог быть удален. В этом случае, если параметр WHOHANG был передан — т.е. вызывающий процесс не хочет ждать, раз ни один дочерний процесс не может быть удален — осуществляется переход к концу с возвратом нуля.

Если был получен сигнал, выполняется выход с ошибкой. Этим сигналом не был SIGCHLD — если бы это было так, мертвый дочерний процесс не был бы найден, и, следовательно, эта точка не была бы достигнута.

В противном случае все в порядке; вызывающему процессу нужно только дождаться выхода дочернего процесса. Таким образом, состояние процесса устанавливается равным TASK_INTERRUPTIBLE и для передачи процессора другому процессу вызывается функция schedule, которая не выполнит возврат до тех пор, пока ожидающий процесс не получит еще один доступ к процессору, во время которого он снова проверит наличие мертвого дочернего процесса (перейдя обратно к метке repeat в строке ). Вспомните, что в состоянии TASK_INTERRUPTIBLE процесс дожидается пробуждения сигналом — в данном случае он специально дожидается сигнала SIGCHLD, показывающего, что дочерний процесс выполнил выход, но ни один сигнал не смог прибыть.

flag имел значение 0, поскольку либо процесс не имел дочерних процессов, либо переданный аргумент pid не совпал ни с одним из его дочерних процессов — в любом случае, функция sys_wait4 возвращает вызывающему процессу ошибку ECHILD.


Содержание раздела