Який файл у ядрі визначає 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");

}

І 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) +++

Це може бути корисним для вас: lxr.linux.no/linux+v3.10.9
повторити

@ mauro.stettler Я не зміг знайти його в lxr
user3539

Ви маєте на увазі git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/… біля лінії 1700? Що ви сподівалися дізнатися?
msw

Відповіді:


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. Ця функція викликає статику clone_process(), яка створює новий процес як копію батьківського, але ще не запускає його. clone_process()копіює регістри, присвоює PID новому завданню і або дублює, або ділиться відповідними частинами технологічного середовища, як зазначено клоном flags. Коли clone_process()повернеться, do_clone()розбудить новостворений процес і запланує його запуск.


2
+1 Приємне пояснення значущості clone()по відношенню до ниток та вилок.
goldilocks


2

Компонент, відповідальний за переклад функцій системного виклику userland в системні виклики ядра під Linux, є libc. У GLibC бібліотека NPTL перенаправляє це до clone(2)системного виклику.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.