Задание завершено настолько, насколько остается возможность передать необходимую информацию родительскому процессу.
Удаление дескриптора процесса
После возврата из функции do_exit
TASK_ZOMBIE и не может выполняться. Как уже рассказывалось выше, это позволяет системе получить информацию о порожденном процессе после его завершения. Следовательно, завершение процесса и удаление его дескриптора происходят в разные моменты времени. После того как родительский процесс получил информацию о завершенном порожденном процессе, структура task_struct порожденного процесса освобождается.Семейство функций wait
wait4. Стандартное поведение этой функции — приостановить выполнение вызывающей задачи до тех пор, пока один из ее порожденных процессов не завершится. При этом возвращается идентификатор PID завершенного порожденного процесса. В дополнение к этому, в данную функцию передается указатель на область памяти, которая после возврата из функции будет содержать код завершения завершившегося порожденного процесса.Когда приходит время окончательно освободить дескриптор процесса, вызывается функция release_task
• Вызывается функция free_uid
• Вызывается функция unhash_process
pidhash и удаления задачи из списка задач.• Если задача была в состоянии трассировки (
• В конце концов вызывается функция put_task_struct
thread_info, a также освобождается слябовый кэш, содержащий структуру task_struct.На данном этапе дескриптор процесса, а также все ресурсы, которые принадлежали только этому процессу, освобождены.
Дилемма "беспризорного" процесса
Если родительский процесс завершается до того, как завершаются вес его потомки, то должен существовать какой-нибудь механизм назначения нового родительского процесса для порожденных, иначе процессы, у которых нет родительского, навсегда останутся в состоянии зомби, что будет зря расходовать системную память. Решение этой проблемы было указано выше: новым родительским процессом становится или какой-либо один поток из группы потоков завершившегося родительского процесса, или процесс 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);
}