Que arquivo no kernel especifica fork (), vfork ()… para usar a chamada de sistema sys_clone ()

8

Quando o ltrace é usado para rastrear as chamadas do sistema, pude ver que fork () usa sys_clone () em vez de sys_fork (). Mas eu não encontrei a fonte Linux onde ela 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 do 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, "7ELF
#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");

}
2
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, "7ELF%pre%2%pre%1%pre%1", 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) +++
1%pre%1", 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) +++
    
por user3539 21.08.2013 / 04:46

2 respostas

28

Os invólucros fork() e vfork() na glibc são implementados por meio da chamada do sistema clone() . Para entender melhor o relacionamento entre fork() e clone() , devemos considerar a relação entre processos e threads no Linux.

Tradicionalmente, fork() publica todos os recursos pertencentes ao processo pai e atribui a cópia ao processo filho. Essa abordagem incorre em uma sobrecarga considerável, o que pode ser por nada se a criança chamar imediatamente exec() . No Linux, fork() utiliza as páginas copy-on-write para atrasar ou evitar a cópia dos dados que podem ser compartilhados entre os processos pai e filho. Assim, a única sobrecarga incorrida durante um% normal fork() é a cópia das tabelas de páginas pai e a atribuição de uma estrutura exclusiva do descritor de processo, task_struct , para o filho.

O Linux também tem 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 para os encadeamentos em comparação com outros sistemas operacionais, como o Windows ou o Solaris, em que processos e encadeamentos são tipos totalmente diferentes de animais. No Linux, cada thread tem um task_struct comum que por si só é configurado de tal forma que compartilha certos recursos, como um espaço de endereço, com o processo pai.

O parâmetro flags da chamada de sistema clone() inclui um conjunto de sinalizadores que indicam quais recursos, se houver, devem ser compartilhados pelos processos pai e filho. Processos e encadeamentos são criados por meio de clone() , a única diferença é o conjunto de sinalizadores passado para clone() .

Um fork() normal pode ser implementado como:

clone(SIGCHLD, 0);

Isso cria uma tarefa que não compartilha nenhum recurso com seu pai e está configurada para enviar o sinal SIGCHLD de terminação para o pai quando ele sai.

Por outro lado, uma tarefa que compartilha o espaço de endereço, recursos do sistema de arquivos, descritores de arquivo e manipuladores de sinais com o pai, em outras palavras, um thread , pode ser criado com:

clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);

vfork() , por sua vez, é implementado por meio de um sinalizador CLONE_VFORK separado, o que fará com que o processo pai seja suspenso até que o processo filho o acorde por meio de um sinal. O filho será o único thread de execução no namespace do pai, até chamar exec() ou exits. A criança não tem permissão para escrever na memória. A chamada clone() correspondente pode ser a seguinte:

clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)

A implementação de sys_clone() é específica da arquitetura, mas a maior parte do trabalho acontece em do_fork() definido em kernel/fork.c . Essa função chama o static clone_process() , que cria um novo processo como uma cópia do pai, mas ainda não o inicia. clone_process() copia os registradores, atribui um PID à nova tarefa e publica ou compartilha partes apropriadas do ambiente de processo, conforme especificado pelo clone flags . Quando clone_process() retornar, do_clone() irá ativar o processo recém-criado e agendá-lo para ser executado.

    
por 21.08.2013 / 22:14
2

O componente responsável por traduzir as funções de chamada do sistema do sistema operacional para as chamadas do sistema kernel no Linux é o libc. No GLibC, a biblioteca NPTL redireciona isso para a chamada do sistema clone(2) .

    
por 21.08.2013 / 05:30