Задание завершено настолько, насколько остается возможность передать необходимую информацию родительскому процессу.

<p>Удаление дескриптора процесса</p>

После возврата из функции do_exit дескриптор завершенного процесса все еще существует в системе, но процесс находится в состоянии TASK_ZOMBIE и не может выполняться. Как уже рассказывалось выше, это позволяет системе получить информацию о порожденном процессе после его завершения. Следовательно, завершение процесса и удаление его дескриптора происходят в разные моменты времени. После того как родительский процесс получил информацию о завершенном порожденном процессе, структура task_struct порожденного процесса освобождается.

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

Когда приходит время окончательно освободить дескриптор процесса, вызывается функция release_task, которая выполняет указанные ниже операции.

• Вызывается функция free_uid для декремента счетчика ссылок на информацию о пользователе процесса. В системе Linux поддерживается кэш с информацией о каждом пользователе, в частности сколько процессов и открытых файлов имеет пользователь. Если счетчик ссылок достигает значения нуль, то пользователь больше не имеет запущенных процессов и открытых файлов, в результате кэш уничтожается.

• Вызывается функция unhash_process для удаления процесса из хеш-таблицы идентификаторов процессов pidhash и удаления задачи из списка задач.

• Если задача была в состоянии трассировки (ptrace), то родительским для нее снова назначается первоначальный родительский процесс и задача удаляется из списка задач, которые находятся в состоянии трассировки (ptrace) данным процессом.

• В конце концов вызывается функция put_task_struct для освобождения страниц памяти, содержащих стек ядра процесса и структуру thread_info, a также освобождается слябовый кэш, содержащий структуру task_struct.

На данном этапе дескриптор процесса, а также все ресурсы, которые принадлежали только этому процессу, освобождены.

<p>Дилемма "беспризорного" процесса</p>

Если родительский процесс завершается до того, как завершаются вес его потомки, то должен существовать какой-нибудь механизм назначения нового родительского процесса для порожденных, иначе процессы, у которых нет родительского, навсегда останутся в состоянии зомби, что будет зря расходовать системную память. Решение этой проблемы было указано выше: новым родительским процессом становится или какой-либо один поток из группы потоков завершившегося родительского процесса, или процесс init. При выполнении функции do_exit вызывается функция notify_parent, которая в свою очередь вызывает forget_original_parent для осуществления переназначения родительского процесса (reparent), как показано ниже.

struct task_struct *p, *reaper = father;

struct list_head *list;

if (father->exit_signal != -1)

 reaper = prev_thread(reaper);

else

 reaper = child_reaper;

if (reaper == father)

 reaper = child_reaper;

Этот программный код присваивает переменной reaper указатель на другое задание в группе потоков данного процесса. Если в этой группе потоков нет другого задания, то переменной reaper присваивается значение переменной child_reaper, которая содержит указатель на процесс init. Теперь, когда найден подходящий родительский процесс, нужно найти все порожденные процессы и установить для них полученное значение родительского процесса, как показано ниже.

list_for_each(list, &father->children) {

 p = list_entry(list, struct task_struct, sibling);

 reparent_thread(p, reaper, child_reaper);

}

list_for_each(list, &father->ptrace_children) {

 p = list_entry(list, struct task_struct, ptrace_list);

 reparent_thread(p, reaper, child_reaper);

}

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже