Por que um filho de um vfork ou fork chama _exit () em vez de exit ()?

12

Na página do manual de vfork():

vfork () difere de fork () porque o pai é suspenso até que o filho faça uma chamada para execve (2) ou _exit (2). O filho compartilha toda a memória com seu pai, incluindo a pilha, até execve () ser emitido pelo filho. O filho não deve retornar da função atual ou chamar exit (), mas pode chamar _exit ().

Por que a criança deveria usar um _exit()chamado, em vez de simplesmente exit()? Espero que isso seja aplicável a ambos vfork()e fork().

Sen
fonte
2
Se você estiver interessado em uma anterior discussão de ontopic-ness de chamadas de API unix C
xenoterracide

Respostas:

11

Como visto anteriormente , vforknão permite que o processo filho acesse a memória dos pais. exité uma função da biblioteca C (é por isso que geralmente é escrita como exit(3)). Ele executa várias tarefas de limpeza, como liberação e fechamento de fluxos C (os arquivos são abertos por meio de funções declaradas em stdio.h) e execução de funções especificadas pelo usuário registradas atexit. Todas essas tarefas envolvem leitura e gravação na memória do processo.

_exitsai sem limpeza. É diretamente uma chamada do sistema (e é por isso que está escrita como _exit(2)), normalmente implementada colocando o número da chamada do sistema em um registro do processador e executando uma instrução específica do processador (ramificação para o manipulador de chamadas do sistema). Isso não precisa acessar a memória do processo, portanto é seguro fazê-lo depois vfork.

Depois fork, não há essa restrição: o processo pai e filho agora são completamente autônomos.

Gilles 'SO- parar de ser mau'
fonte
O vfork não permite que o processo filho acesse a memória dos pais ? Mas eu pensei que eles compartilham o mesmo espaço de endereço, para que a criança possa acessar o espaço de endereço dos pais. Esse entendimento estava errado?
Sen
Após a bifurcação, não há essa restrição: o processo pai e filho agora são completamente autônomos. Isso significa que eu posso chamar uma saída () de um filho de um garfo?
Sen
1
@ Sen: O filho não tem permissão para acessar a memória dos pais. Se você tentar, pode funcionar, porque o kernel não o protegerá. Mas o efeito pode não ser o que você pretende; por exemplo, se seu compilador decidir deixar algum valor em um registro, ele não será visto pelo processo pai.
Gilles 'SO- stop be evil'
@ Sen: Depois de uma bifurcação, você pode chamar exit ou qualquer outra função. Todo processo inicia após um fork (no Linux, mesmo o processo inicial inité bifurcado pelo kernel).
Gilles 'SO- stop be evil'
3

exitfaça uma limpeza adicional, como chamar funções registradas e, atexitportanto, acessar dados fora da parte copiada. _exitexecuta syscall diretamente sem qualquer limpeza, exceto no kernel.

Maciej Piechotka
fonte
... e deve-se notar que o fork () copia tudo, então você pode chamar exit () e definitivamente pode retornar da função atual.
derobert
3

Você tem o filho chamado _exit () para evitar a descarga de buffers stdio (ou outros) quando o processo filho é encerrado. Como o processo filho constitui uma cópia exata do processo pai, o processo filho ainda possui o que o pai tinha em "stdout" ou "stderr", os buffers de <stdio.h>. Você pode (e, em momentos inoportunos) obter saídas duplas chamando exit (), uma dos manipuladores atexit do processo filho e uma do pai, quando os buffers no processo pai ficam cheios e são liberados.

Sei que a resposta acima se concentra nas especificidades do stdio.h, mas essa ideia provavelmente é transferida para outras E / S com buffer, exatamente como uma das respostas acima indica.

Bruce Ediger
fonte
1

exit(): - executa algumas tarefas de limpeza, como fechar os fluxos de E / S e muitos, e depois retorna ao kernel. _exit(): - chega diretamente ao kernel (não execute nenhuma tarefa de limpeza).

fork() : pai e filho têm uma tabela de arquivos diferente, portanto, as alterações feitas pelo filho não afetam os parâmetros de ambiente do pai e vice-versa.

vfork(): pai e filho usam a mesma tabela de arquivos, portanto, a alteração feita pelo filho afeta os parâmetros de ambiente do pai. por exemplo, alguma variável var=10, agora executada var++por filho e, em seguida, execute pai, você também pode ver o efeito var++na saída do pai.

Como eu disse, se você usar exit()em vfork()seguida, toda a E / S já está fechado. Portanto, mesmo que o pai seja executado corretamente, você não poderá obter a saída adequada, porque todas as variáveis ​​estão niveladas e todos os fluxos estão fechados.

user2670535
fonte