No contexto de sistemas operacionais, a destruição de processos é um procedimento crítico gerenciado pelo kernel, envolvendo chamadas de sistema como exit e waitpid. Este processo assegura a liberação adequada de recursos e a comunicação entre processos pai e filho.
Quando um processo é encerrado via exit, o kernel executa uma série de etapas. Inicialmente, a memória associada aos segmentos de código e dados é liberada. Em seguida, todos os arquivos abertos pelo processo são fechados, e as operações de sincronização com o diretório atual e nós i são realizadas. Se o processo possuir filhos, eles são reatribuídos ao processo init (PID 1). Além disso, se o processo for o líder de uma sessão, todos os processos dessa sessão são terminados. O estado do processo é alterado para zumbi, e um sinal SIGCHLD é enviado ao processo pai.
O processo pai normalmente invoca wait ou waitpid para monitorar o término dos filhos. Ao receber SIGCHLD, o pai encerra o processo zumbi, acumula os tempos de execução do filho nas suas próprias variáveis e libera a estrutura de descrição do processo filho, além de limpar a tabela de tarefas e liberar páginas de memória associadas.
Abaixo, exemplos de código reeescritos em C, com alterações na estrutura, nomes de variáveis e lógica, mantendo a funcionalidade original:
int enviar_sinal(int alvo_pid, int sinal) {
struct tarefa_struct **ptr = tabela_tarefas + NUM_TAREFAS;
int erro, resultado = 0;
if (!alvo_pid) {
while (--ptr > &TAREFA_INICIAL) {
if (*ptr && (*ptr)->grupo_processo == processo_atual->pid) {
erro = sinalizar(sinal, *ptr, 1);
if (erro) resultado = erro;
}
}
} else if (alvo_pid > 0) {
while (--ptr > &TAREFA_INICIAL) {
if (*ptr && (*ptr)->pid == alvo_pid) {
erro = sinalizar(sinal, *ptr, 0);
if (erro) resultado = erro;
}
}
} else if (alvo_pid == -1) {
while (--ptr > &TAREFA_INICIAL) {
erro = sinalizar(sinal, *ptr, 0);
if (erro) resultado = erro;
}
} else {
while (--ptr > &TAREFA_INICIAL) {
if (*ptr && (*ptr)->grupo_processo == -alvo_pid) {
erro = sinalizar(sinal, *ptr, 0);
if (erro) resultado = erro;
}
}
}
return resultado;
}
int encerrar_processo(long codigo_saida) {
int indice;
liberar_tabelas_paginas(obter_base(processo_atual->ldt[1]), obter_limite(0x0f));
liberar_tabelas_paginas(obter_base(processo_atual->ldt[2]), obter_limite(0x17));
for (indice = 0; indice < NUM_TAREFAS; indice++) {
if (tabela_tarefas[indice] && tabela_tarefas[indice]->pai == processo_atual->pid) {
tabela_tarefas[indice]->pai = 1;
if (tabela_tarefas[indice]->estado == ESTADO_ZUMBI) {
sinalizar(SIGCHLD, tabela_tarefas[1], 1);
}
}
}
for (indice = 0; indice < MAX_ARQUIVOS; indice++) {
if (processo_atual->descritores_arquivo[indice]) {
fechar_arquivo(indice);
}
}
liberar_no_i(processo_atual->diretorio_trabalho);
processo_atual->diretorio_trabalho = NULL;
liberar_no_i(processo_atual->raiz);
processo_atual->raiz = NULL;
liberar_no_i(processo_atual->executavel);
processo_atual->executavel = NULL;
if (processo_atual->lider && processo_atual->terminal >= 0) {
tabela_terminal[processo_atual->terminal].grupo_processo = 0;
}
if (ultimo_processo_coprocessador == processo_atual) {
ultimo_processo_coprocessador = NULL;
}
if (processo_atual->lider) {
terminar_sessao();
}
processo_atual->estado = ESTADO_ZUMBI;
processo_atual->codigo_saida = codigo_saida;
notificar_pai(processo_atual->pai);
reagendar();
return (-1);
}
int esperar_processo(int pid_filho, unsigned long *endereco_status, int opcoes) {
int achou, codigo_saida;
struct tarefa_struct **iterador;
verificar_area(endereco_status, 4);
repetir:
achou = 0;
for (iterador = &ULTIMA_TAREFA; iterador > &PRIMEIRA_TAREFA; --iterador) {
if (!*iterador || *iterador == processo_atual) {
continue;
}
if ((*iterador)->pai != processo_atual->pid) {
continue;
}
if (pid_filho > 0) {
if ((*iterador)->pid != pid_filho) {
continue;
}
} else if (!pid_filho) {
if ((*iterador)->grupo_processo != processo_atual->grupo_processo) {
continue;
}
} else if (pid_filho != -1) {
if ((*iterador)->grupo_processo != -pid_filho) {
continue;
}
}
switch ((*iterador)->estado) {
case ESTADO_PARADO:
if (!(opcoes & WUNTRACED)) {
continue;
}
escrever_no_usuario(0x7f, endereco_status);
return (*iterador)->pid;
case ESTADO_ZUMBI:
processo_atual->tempo_usuario_filho += (*iterador)->tempo_usuario;
processo_atual->tempo_sistema_filho += (*iterador)->tempo_sistema;
achou = (*iterador)->pid;
codigo_saida = (*iterador)->codigo_saida;
liberar_tarefa(*iterador);
escrever_no_usuario(codigo_saida, endereco_status);
return achou;
default:
achou = 1;
continue;
}
}
if (achou) {
if (opcoes & WNOHANG) {
return 0;
}
processo_atual->estado = ESTADO_INTERRUPTIVEL;
reagendar();
if (!(processo_atual->sinal &= ~(1 << (SIGCHLD - 1)))) {
goto repetir;
} else {
return -EINTR;
}
}
return -ECHILD;
}