Если указать флаг CLONE_PID, потомок будет иметь такой же идентификатор, как его родитель. В противном случае родитель и потомок получают разные идентификаторы PID (как в случае с fork() и vfork()). Этот флаг может устанавливать только процесс загрузки системы (тот, чей PID равен 0); он используется во время инициализации мультипроцессорных систем.

Флаг CLONE_PID не предназначен для применения в пользовательских приложениях. Он больше не доступен в Linux 2.6, а ему на замену пришел флаг CLONE_IDLETASK, который приводит к тому, что идентификатор нового процесса равняется 0. Флаг CLONE_IDLETASK доступен только для внутреннего применения в ядре и игнорируется вызовом clone(). Он используется для создания невидимых процессов, находящихся в режиме ожидания; каждый такой процесс отводится для отдельного ЦПУ (в многопроцессорных системах их может быть несколько).

Трассировка процессов: CLONE_PTRACE и CLONE_UNTRACED

Если указать флаг CLONE_PTRACE, потомок трассируемого процесса тоже будет трассироваться. Подробности о трассировке процессов (которая используется при отладке и в команде strace) ищите на справочной странице ptrace(2).

В версиях Linux 2.6 и выше можно указывать флаг CLONE_UNTRACED, который не позволяет трассируемому процессу применить флаг CLONE_PTRACE к своему потомку. Он используется внутри системы для создания потоков ядра.

Приостановка родителя до тех пор, пока потомок не завершится или не выполнит exec: CLONE_VFORK

Если указать флаг CLONE_VFORK, выполнение родителя приостанавливается до тех пор, пока потомок не освободит ресурсы своей виртуальной памяти с помощью вызовов exec() или _exit() (как в случае с vfork()).

Новые флаги вызова clone() для поддержки контейнеров

В Linux 2.6.19 и выше появилась поддержка целого ряда новых флагов для вызова clone(): CLONE_IO, CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWPID, CLONE_NEWUSER и CLONE_NEWUTS (см. справочную страницу clone(2)).

Большинство из этих флагов обеспечивают поддержку контейнеров ([Bhattiprolu et al., 2008]). Контейнер — это разновидность легковесной виртуализации, при которой группы процессов, выполняющихся на одном ядре, могут быть изолированы друг от друга в средах, напоминающих отдельные компьютеры. Контейнеры также могут быть вложенными, один внутри другого. Данный подход отличается от полноценной виртуализации, при которой каждая виртуальная среда работает на отдельном ядре.

Для реализации контейнеров разработчикам Linux пришлось создать в ядре виртуальный слой вокруг каждого глобального ресурса системы — это, например, касается идентификаторов процессов, сетевого стека, идентификаторов, возвращаемых вызовом uname(), IPC-объектов из System V, а также пространств имен для идентификаторов пользователей и групп. Благодаря этому каждый контейнер может получить собственный экземпляр этих ресурсов.

Контейнеры имеют множество различных применений, включая следующие:

• контроль над выделением ресурсов системы, таких как пропускная способность сети или процессорное время (например, одному контейнеру можно выдать 75 % процессорного времени, а другому — 25 %);

• предоставление нескольких легковесных виртуальных серверов на одном и том же компьютере;

• замораживание контейнера, чтобы приостановить выполнение всех процессов внутри него и позже, возможно после миграции на другой компьютер, запустить их заново;

• возможность сбросить на диск состояние приложения (создав тем самым контрольную точку) и затем восстановить его (возможно, после аварийного завершения программы или плановой/неплановой перезагрузки системы), чтобы продолжить выполнение с того самого места.

Использование флагов вызова clone()

Вызов fork(), грубо говоря, соответствует вызову clone(), аргумент flags которого равен SIGCHLD, тогда как vfork() соответствует clone() со следующими флагами:

CLONE_VM | CLONE_VFORK | SIGCHLD

Обертка fork() библиотеки glibc версии 2.3.3 и выше, которая входит в состав реализации NPTL-потоков, обходит одноименный системный вызов и обращается вместо него к вызову clone(). Эта функция запускает любые обработчики, установленные вызывающим процессом с помощью pthread_atfork() (см. раздел 33.3).

В библиотеке LinuxThreads для создания потоков вызов clone() (но только с первыми четырьмя его аргументами) применяется в сочетании со следующими флагами:

CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_SIGHAND

В библиотеке NPTL вызов clone() (вместе со всеми семью его аргументами) создает потоки с помощью таких флагов:

CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_SIGHAND | CLONE_THREAD | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM

28.2.2. Расширения к вызову waitpid() для клонированных потомков

Перейти на страницу:

Похожие книги