Quando ltrace é usado para rastrear as chamadas do sistema, pude ver que fork () usa sys_clone () em vez de sys_fork (). Mas não consegui encontrar a fonte linux onde está definida.
Meu programa é
#include<stdio.h>
main()
{
int pid,i=0,j=0;
pid=fork();
if(pid==0)
printf("\nI am child\n");
else
printf("\nI am parent\n");
}
E a saída ltrace é
SYS_brk(NULL) = 0x019d0000
SYS_access("/etc/ld.so.nohwcap", 00) = -2
SYS_mmap(0, 8192, 3, 34, 0xffffffff) = 0x7fe3cf84f000
SYS_access("/etc/ld.so.preload", 04) = -2
SYS_open("/etc/ld.so.cache", 0, 01) = 3
SYS_fstat(3, 0x7fff47007890) = 0
SYS_mmap(0, 103967, 1, 2, 3) = 0x7fe3cf835000
SYS_close(3) = 0
SYS_access("/etc/ld.so.nohwcap", 00) = -2
SYS_open("/lib/x86_64-linux-gnu/libc.so.6", 0, 00) = 3
SYS_read(3, "\177ELF\002\001\001", 832) = 832
SYS_fstat(3, 0x7fff470078e0) = 0
SYS_mmap(0, 0x389858, 5, 2050, 3) = 0x7fe3cf2a8000
SYS_mprotect(0x7fe3cf428000, 2097152, 0) = 0
SYS_mmap(0x7fe3cf628000, 20480, 3, 2066, 3) = 0x7fe3cf628000
SYS_mmap(0x7fe3cf62d000, 18520, 3, 50, 0xffffffff) = 0x7fe3cf62d000
SYS_close(3) = 0
SYS_mmap(0, 4096, 3, 34, 0xffffffff) = 0x7fe3cf834000
SYS_mmap(0, 4096, 3, 34, 0xffffffff) = 0x7fe3cf833000
SYS_mmap(0, 4096, 3, 34, 0xffffffff) = 0x7fe3cf832000
SYS_arch_prctl(4098, 0x7fe3cf833700, 0x7fe3cf832000, 34, 0xffffffff) = 0
SYS_mprotect(0x7fe3cf628000, 16384, 1) = 0
SYS_mprotect(0x7fe3cf851000, 4096, 1) = 0
SYS_munmap(0x7fe3cf835000, 103967) = 0
__libc_start_main(0x40054c, 1, 0x7fff47008298, 0x4005a0, 0x400590 <unfinished ...>
fork( <unfinished ...>
SYS_clone(0x1200011, 0, 0, 0x7fe3cf8339d0, 0) = 5967
<... fork resumed> ) = 5967
puts("\nI am parent" <unfinished ...>
SYS_fstat(1, 0x7fff47008060) = 0
SYS_mmap(0, 4096, 3, 34, 0xffffffff
) = 0x7fe3cf84e000
I am child
SYS_write(1, "\n", 1
) = 1
SYS_write(1, "I am parent\n", 12) = -512
--- SIGCHLD (Child exited) ---
SYS_write(1, "I am parent\n", 12I am parent
) = 12
<... puts resumed> ) = 13
SYS_exit_group(13 <no return ...>
+++ exited (status 13) +++
linux
linux-kernel
system-calls
trace
ltrace
user3539
fonte
fonte
Respostas:
Os wrappers
fork()
evfork()
na glibc são implementados através daclone()
chamada do sistema. Para entender melhor o relacionamento entrefork()
eclone()
, devemos considerar o relacionamento entre processos e threads no Linux.Tradicionalmente,
fork()
publicaria todos os recursos pertencentes ao processo pai e atribuiria a cópia ao processo filho. Essa abordagem gera uma sobrecarga considerável, que pode ser inútil se a criança ligar imediatamenteexec()
. No Linux,fork()
utiliza páginas de cópia na gravação para atrasar ou evitar completamente a cópia dos dados que podem ser compartilhados entre os processos pai e filho. Portanto, a única sobrecarga incorrida durante um normalfork()
é a cópia das tabelas de páginas dos pais e a atribuição de uma estrutura de descritor de processo exclusivatask_struct
, para o filho.O Linux também adota uma abordagem excepcional para threads. No Linux, os threads são meramente processos comuns que compartilham alguns recursos com outros processos. Essa é uma abordagem radicalmente diferente dos threads em comparação com outros sistemas operacionais, como Windows ou Solaris, onde processos e threads são tipos totalmente diferentes de bestas. No Linux, cada encadeamento possui um ordinário
task_struct
próprio que, por acaso, é configurado de forma a compartilhar certos recursos, como um espaço de endereço, com o processo pai.O
flags
parâmetro daclone()
chamada do sistema inclui um conjunto de sinalizadores que indicam quais recursos, se houver, os processos pai e filho devem compartilhar. Processos e threads são criados viaclone()
, a única diferença é o conjunto de sinalizadores aos quais são passadosclone()
.Um normal
fork()
pode ser implementado como:Isso cria uma tarefa que não compartilha nenhum recurso com seu pai e é configurada para enviar o
SIGCHLD
sinal de finalização ao pai quando ele sair.Por outro lado, uma tarefa que compartilha o espaço de endereço, recursos do sistema de arquivos, descritores de arquivo e manipuladores de sinal com o pai, ou seja, um encadeamento , pode ser criada com:
vfork()
por sua vez, é implementado através de umCLONE_VFORK
sinalizador separado , o que fará com que o processo pai durma até que o processo filho o ative por meio de um sinal. O filho será o único encadeamento de execução no namespace do pai, até que ele chameexec()
ou saia. A criança não tem permissão para gravar na memória. Aclone()
chamada correspondente pode ser a seguinte:A implementação de
sys_clone()
é específica da arquitetura, mas a maior parte do trabalho ocorre emdo_fork()
definido emkernel/fork.c
. Essa função chama estáticaclone_process()
, que cria um novo processo como uma cópia do pai, mas ainda não o inicia.clone_process()
copia os registros, atribui um PID à nova tarefa e publica ou compartilha partes apropriadas do ambiente do processo, conforme especificado pelo cloneflags
. Quandoclone_process()
retornar,do_clone()
ativará o processo recém-criado e o agendará para execução.fonte
clone()
em relação a roscas e garfos.O componente responsável por converter as funções de chamada do sistema da terra do usuário em chamadas de sistema do kernel no Linux é a libc. No GLibC, a biblioteca NPTL redireciona isso para a
clone(2)
chamada do sistema.fonte