Какой файл в ядре определяет fork (), vfork ()… для использования системного вызова sys_clone ()

9

Когда для отслеживания системных вызовов используется ltrace, я вижу, что fork () использует sys_clone (), а не sys_fork (). Но я не смог найти источник Linux, где он определен.

Моя программа

#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");

}

И вывод трассировки

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) +++
user3539
источник
Это может быть полезно для вас: lxr.linux.no/linux+v3.10.9
повтор
@ mauro.stettler Я не смог найти его в lxr
user3539
Вы имеете в виду git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/… около строки 1700? Что ты надеялся узнать?
MSS

Ответы:

29

В fork()и vfork()упаковщики в Glibc реализуются через clone()системный вызов. Чтобы лучше понять отношения между fork()и clone(), мы должны рассмотреть отношения между процессами и потоками в Linux.

Традиционно fork()дублирует все ресурсы, принадлежащие родительскому процессу, и назначает копию дочернему процессу. Этот подход влечет за собой значительные накладные расходы, которые могут быть напрасны, если ребенок немедленно звонит exec(). В Linux fork()использует страницы копирования при записи, чтобы задержать или вообще избежать копирования данных, которые могут быть разделены между родительским и дочерним процессами. Таким образом, единственные накладные расходы, которые возникают во время нормального fork()режима, - это копирование таблиц родительской страницы и присвоение уникальной структуры дескриптора процесса task_structдля дочернего элемента .

Linux также использует исключительный подход к потокам. В Linux потоки - это просто обычные процессы, которые совместно используют некоторые ресурсы с другими процессами. Это радикально иной подход к потокам по сравнению с другими операционными системами, такими как Windows или Solaris, где процессы и потоки - это совершенно разные звери. В Linux у каждого потока есть task_structсвой собственный обычный элемент, который просто настраивается таким образом, что он совместно использует определенные ресурсы, такие как адресное пространство, с родительским процессом.

flagsПараметр clone()системного вызова включает в себя набор флагов , которые указывают , какие ресурсы, если таковые имеются, родительские и дочерние процессы должны делиться. Оба процесса и потоки создаются с помощью clone()единственного различия - это набор флагов, которые передаются clone().

Нормальный fork()может быть реализован как:

clone(SIGCHLD, 0);

Это создает задачу, которая не разделяет какие-либо ресурсы со своим родителем, и настроена на отправку SIGCHLDсигнала завершения родителю при выходе.

Напротив, задача, которая совместно использует родительское адресное пространство, ресурсы файловой системы, файловые дескрипторы и обработчики сигналов, другими словами, поток , может быть создана с помощью:

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

vfork()в свою очередь, реализуется через отдельный CLONE_VFORKфлаг, который заставит родительский процесс в спящем режиме, пока дочерний процесс не разбудит его через сигнал. Дочерний объект будет единственным потоком выполнения в пространстве имен родителя, пока он не вызовет exec()или не завершит работу. Ребенок не имеет права писать в память. Соответствующий clone()вызов может быть следующим:

clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)

Реализация sys_clone()зависит от архитектуры, но основная часть работы выполняется в do_fork()соответствии с kernel/fork.c. Эта функция вызывает static clone_process(), который создает новый процесс как копию родительского, но еще не запускает его. clone_process()копирует регистры, назначает PID новой задаче и дублирует или разделяет соответствующие части среды процесса, как указано в клоне flags. Когда clone_process()вернется, do_clone()разбудит только что созданный процесс и запланирует его запуск.

Томас Найман
источник
2
+1 Приятное объяснение значимости по clone()отношению к нитям и вилкам.
Златовласка
1
Удалили все мои сомнения
user3539
2

Компонентом, отвечающим за перевод функций системного вызова пользовательского интерфейса в системные вызовы ядра в Linux, является libc. В GLibC библиотека NPTL перенаправляет это на clone(2)системный вызов.

Игнасио Васкес-Абрамс
источник