ИМЯ
clone, __clone2 -
    создать
    процесс-потомок
ОБЗОР
/* Прототип обёрточной функции glibc */
#define _GNU_SOURCE
#include <sched.h>
int clone(int (*fn)(void *), void *child_stack,
          int flags, void *arg, ... 
          /* pid_t *ptid, void *newtls, pid_t *ctid */ );
/* для прототипа неструктурированного системного вызова, смотрите ЗАМЕЧАНИЯ */
ОПИСАНИЕ
Вызов clone()
    создаёт
    новый
    процесс
    подобно fork(2).
Здесь
    описана
    обёрточная
    функция glibc
    clone() и
    используемый
    ею
    системный
    вызов. В
    основном,
    описывается
    обёрточная
    функция;отличия
    от
    системного
    вызова
    приводятся
    в конце
    данной
    справочной
    страницы.
В отличие
    от fork(2), clone()
    позволяет
    процессу-потомку
    использовать
    некоторые
    части
    контекста
    выполнения
    совместно
    с
    вызывающим
    процессом,
    например:
    виртуальное
    адресное
    пространство,
    таблица
    файловых
    дескрипторов
    и таблица
    обработчиков
    сигналов.
    Заметим,
    что в
    данной
    справочной
    странице
    «вызывающий
    процесс»
    обычно
    соответствует
    «родительскому
    процессу».
    Но
    смотрите
    ниже
    описание
    CLONE_PARENT.
Одним из
    вариантов
    использования
    вызова clone()
    является
    реализация
    нитей:
    несколько
    потоков
    управления
    в
    программе,
    выполняющиеся
    одновременно
    в общем
    адресном
    пространстве.
Когда
    процесс-потомок
    создаётся
    с помощью
    clone(), он
    начинает
    выполнение
    с вызова
    функции, на
    которую
    указывает
    fn (это
    отличается
    от fork(2), где
    выполнение
    продолжается
    в потомке
    от точки
    вызова fork(2)).
    Аргумент arg
    передаётся
    в функцию
  fn.
Когда
    происходит
    возврат из
    функции
    fn(arg)
    процесс-потомок
    завершается.
    Целое
    значение,
    возвращаемое
    fn, является
    состоянием
    выхода
    процесса-потомка.
    Процесс-потомок
    может
    также быть
    завершён
    явным
    образом с
    помощью
    вызова exit(2)
    или после
    получения
    завершающего
    сигнала.
Аргумент
    child_stack задаёт
    положение
    стека,
    используемого
    процессом-потомком.
    Так как
    процесс-потомок
    и
    вызывающий
    процесс
    могут
    использовать
    общую
    память,
    процесс-потомок
    не может
    выполняться
    в том же
    стеке, что и
    вызывающий
    процесс.
    Поэтому
    вызывающий
    процесс
    должен
    установить
    пространство
    памяти для
    стека
    процесса-потомка
    и передать
    указатель
    на это
    пространство
    в вызове clone().
    Стеки
    растут
    вниз для
    всех
    процессоров,
    на которых
    работает Linux
    (за
    исключением
    процессоров
    HP PA), так что
    child_stack, обычно,
    указывает
    на
    наибольший
    адрес в
    пространстве
    памяти,
    которое
    устанавливается
    для стека
    процесса-потомка.
Младший
    байт flags
    содержит
    номер
    сигнала
    завершения,
    который
    посылается
    родителю,
    когда
    работа
    потомка
    завершается.
    Если этот
    сигнал
    задаётся
    как нечто
    отличное
    от SIGCHLD, то
    родительский
    процесс
    должен
    задать
    параметр
    __WALL или __WCLONE
    при
    ожидании
    завершения
    работы
    потомка с
    помощью
    вызова wait(2).
    Если
    никакой
    сигнал не
    задан, то
    родительский
    процесс не
    извещается
    сигналом,
    когда
    потомок
    завершается.
Аргумент
    flags состоит
    из одной
    или более
    данных
    ниже
    констант,
    которые
    складываются
    по
    правилам
    битового
    сложения (OR).
    Флагами
    задаёт что
    будет
    общим
    между
    вызывающим
    процессом
    и
    процессом-потомком:
  - CLONE_CHILD_CLEARTID
    (начиная с Linux
    2.5.49)
- Очистить
      (обнулить)
      идентификатор
      (ID) нити
      потомка,
      расположенный
      в ctid в
      памяти
      потомка,
      если
      потомок
      существует,
      и
      активизировать
      futex по этому
      адресу.
      Соответствующий
      адрес
      может быть
      изменён
      системным
      вызовом
      set_tid_address(2).
      Используется
      в
      библиотеках
      работы с
      нитями.
- CLONE_CHILD_SETTID
    (начиная с Linux
    2.5.49)
- Сохранить
      ID нити
      потомка,
      расположенный
      в ctid в
      памяти
      потомка.
      Операция
      сохранения
      завершается
      до
      возврата
      управления
      из clone() в
      пользовательское
      пространство.
- CLONE_FILES
    (начиная с Linux
    2.0)
- Если задан
      флаг CLONE_FILES, то
      вызывающий
      процесс и
      процесс-потомок
      используют
      одну и ту
      же таблицу
      файловых
      дескрипторов.
      Любые
      файловые
      дескрипторы,
      создаваемые
      вызывающим
      процессом
      или
      процессом-потомком,
      также
      доступны и
      в другом
      процессе.
      Аналогично,
      если один
      из
      процессов
      закрывает
      файловый
      дескриптор
      или
      изменяет
      ассоциированные
      с ним флаги
      (с помощью
      fcntl(2)
      операцией
      F_SETFD), то это
      оказывает
      влияние и
      на другой
      процесс.
      Если
      процесс
      использующий
      общую
      таблицу
      файловых
      дескрипторов
      вызывает
      execve(2), то
      таблица
      файловых
      дескрипторов
      копируется
      в
      отдельную
      (не общую).
  
  - Если флаг
      CLONE_FILES не
      задан, то
      процесс-потомок
      наследует
      копии всех
      файловых
      дескрипторов,
      открытых в
      вызывающем
      процессе
      на момент
      вызова clone().
      Последующие
      операции
      над
      файловыми
      дескрипторами
      по
      открытию и
      закрытию
      файлов или
      изменению
      флагов
      файловых
      дескрипторов,
      выполняемые
      вызывающим
      процессом
      или
      процессом-потомком,
      не
      оказывают
      эффекта на
      другой
      процесс.
      Заметим,
      что
      дублируемые
      файловые
      дескрипторы
      в потомке
      указывают
      на те же
      открытые
      файловые
      дескрипторы
      что и
      файловые
      дескрипторы
      вызывающего
      процесса и,
      таким
      образом,
      файловые
      смещения и
      флаги
      состояния
      файла
      используются
      совместно
      (смотрите
      open(2)).
  - CLONE_FS
    (начиная с Linux
    2.0)
- Если задан
      флаг CLONE_FS, то
      вызывающий
      процесс и
      процесс-потомок
      используют
      одну и ту
      же
      информацию
      о файловой
      системе. К
      ней
      относится
      корневой
      каталог
      файловой
      системы,
      текущий
      рабочий
      каталог и
      значение umask.
      Любой
      вызов, chroot(2),
      chdir(2) или umask(2),
      выполняемый
      одним
      процессом,
      оказывает
      влияние и
      на другой.
  
  - Если флаг
      CLONE_FS не задан,
      то
      процесс-потомок
      работает с
      копией
      информации
      о файловой
      системе
      вызывающего
      процесса,
      снятой на
      момент
      вызова clone().
      Вызовы chroot(2),
      chdir(2) или umask(2),
      выполняемые
      позже
      одним из
      процессов,
      не
      оказывают
      эффект на
      другой
      процесс.
  - CLONE_IO
    (начиная Linux
    2.6.25)
- Если задан
      флаг CLONE_IO, то
      новый
      процесс
      использует
      общий
      контекст
      ввода-вывода
      с
      вызывающим
      процессом.
      Если этот
      флаг не
      установлен,
      то (как и в
      fork(2)) новый
      процесс
      будет
      иметь свой
      отдельный
      контекст
      ввода-вывода.
  
  - Контекст
      ввода-вывода
      — это
      область
      ввода-вывода
      в дисковом
      планировщике
      (т. е. то, что
      планировщик
      ввода-вывода
      использует
      при
      планировании
      ввода-вывода
      процесса).
      Если
      процессы
      используют
      общий
      контекст
      ввода-вывода,
      то они
      рассматриваются
      планировщиком
      ввода-вывода
      как один.
      Следовательно,
      они
      совместно
      делят
      время
      доступа к
      диску. У
      некоторых
      планировщиков
      ввода-вывода,
      если два
      процесса
      используют
      общий
      контекст
      ввода-вывода,
      то им будет
      разрешено
      чередовать
      доступ к
      диску. Если
      несколько
      нитей
      выполняют
      ввод-вывод
      из одного
      процесса
      (например,
      aio_read(3)), то для
      них нужно
      указать CLONE_IO
      для
      получения
      большей
      производительности
      ввода-вывода.
- Если в ядре
      не указан
      параметр
      сборки CONFIG_BLOCK,
      то этот
      флаг ни на
      что не
      влияет.
  - CLONE_NEWCGROUP
    (начиная с Linux
    4.6)
- Процесс
      создаётся
      в новом
      пространстве
      имён cgroup. Если
      флаг не
      установлен,
      то (как и в
      fork(2)), процесс
      создаётся
      в том же
      пространстве
      имён cgroup, что и
      вызывающий
      процесс.
      Этот флаг
      предназначен
      для
      реализации
      контейнеров.
  
  - Дополнительную
      информацию
      о
      пространствах
      имён cgroup
      смотрите в
      cgroup_namespaces(7).
- Только
      привилегированный
      процесс
      (CAP_SYS_ADMIN) может
      использовать
      CLONE_NEWCGROUP.
  - CLONE_NEWIPC
    (начиная с Linux
    2.6.19)
- Если задан
      флаг CLONE_NEWIPC, то
      процесс
      создаётся
      в новом
      пространстве
      имён IPC. Если
      этот флаг
      не
      установлен,
      то (как и в
      fork(2)) процесс
      создаётся
      в том же
      пространстве
      имён IPC что и
      вызывающий
      процесс.
      Этот флаг
      предназначен
      для
      реализации
      контейнеров.
  
  - Пространство
      имён IPC
      предоставляет
      изолированную
      выборку
      объектов
      System V IPC
      (смотрите
      svipc(7)) и
      (начиная с Linux
      2.6.30) очередей
      сообщений
      POSIX (смотрите
      mq_overview(7)). Общие
      характеристики
      этих
      механизмов
      IPC в том, что
      объекты IPC
      определяются
      механизмами,
      а не путями
      в файловой
      системе.
- Объекты,
      созданные
      в
      пространстве
      имён IPC,
      видимы
      всем
      другим
      процессам,
      которые
      являются
      членами
      этого
      пространства
      имён, и
      невидимы
      процессам
      из других
      пространств
      имён IPC.
- При
      уничтожении
      пространства
      имён IPC (т.е.,
      когда
      завершается
      последний
      процесс из
      этого
      пространства
      имён), все
      объекты IPC
      из
      пространства
      имён
      автоматически
      уничтожаются.
- Только
      привилегированный
      процесс
      (CAP_SYS_ADMIN) может
      использовать
      CLONE_NEWIPC. Этот
      флаг
      нельзя
      указывать
      вместе с
      CLONE_SYSVSEM.
- Дополнительную
      информацию
      о
      пространствах
      имён IPC
      смотрите в
      namespaces(7).
  - CLONE_NEWNET
    (начиная с Linux
    2.6.24)
- (Реализация
      этого
      флага
      завершена
      только в Linux
    2.6.29.)
  
  - Если задан
      флаг CLONE_NEWNET, то
      процесс
      создаётся
      в новом
      сетевом
      пространстве
      имён. Если
      флаг не
      установлен,
      то (как и в
      fork(2)), процесс
      создаётся
      в том же
      сетевом
      пространстве
      имён что и
      вызывающий
      процесс.
      Этот флаг
      предназначен
      для
      реализации
      контейнеров.
- Сетевое
      пространство
      имён
      предоставляет
      изолированное
      представление
      сетевого
      стека
      (интерфейсы
      сетевых
      устройств,
      стеки
      протоколов
      IPv4 и IPv6,
      таблицы
      маршрутизации
      IP, правила
      межсетевого
      экрана,
      дерево
      каталогов
      /proc/net и /sys/class/net,
      сокеты и т.
      д.).
      Физическое
      сетевое
      устройство
      может
      находиться
      только в
      одном
      сетевом
      пространстве
      имён. Пара
      виртуальных
      сетевых
      устройств
      (veth(4))
      предоставляет
      похожую на
      канал
      абстракцию,
      которую
      можно
      использовать
      для
      создания
      туннелей
      между
      сетевыми
      пространствами
      имён и
      создания
      моста к
      физическому
      сетевому
      устройству
      из другого
      пространства
      имён.
- Когда
      сетевое
      пространство
      имён
      высвобождается
      (т. е., когда
      завершается
      последний
      процесс в
      пространстве
      имён), его
      физические
      сетевые
      устройства
      перемещаются
      обратно в
      первоначальное
      сетевое
      пространство
      имён (не
      родительского
      процесса).
      Дополнительную
      информацию
      о сетевых
      пространствах
      имён
      смотрите в
      namespaces(7).
- Только
      привилегированный
      процесс
      (CAP_SYS_ADMIN) может
      использовать
      CLONE_NEWNET.
  - CLONE_NEWNS
    (начиная с Linux
    2.4.19)
- Если
      указан
      флаг CLONE_NEWNS, то
      клонированный
      потомок
      запускается
      в новом
      пространстве
      имён
      монтирования,
      инициализированном
      копией
      пространства
      имён
      родителя.
      Если CLONE_NEWNS не
      указан, то
      потомок
      остаётся в
      том же
      пространстве
      имён
      монтирования
      что и
      родитель.
  
  - Только
      привилегированный
      процесс
      (имеющий
      мандат CAP_SYS_ADMIN)
      может
      использовать
      CLONE_NEWNS. Не
      допускается
      совместное
      использование
      флагов CLONE_NEWNS
      и CLONE_FS в одном
      вызове clone().
- Дополнительную
      информацию
      о
      пространствах
      имён
      монтирования
      смотрите в
      namespaces(7) и mount_namespaces(7).
  - CLONE_NEWPID
    (начиная с Linux
    2.6.24)
- Если задан
      флаг CLONE_NEWPID, то
      процесс
      создаётся
      в новом
      пространстве
      имён PID. Если
      флаг не
      установлен,
      то (как и в
      fork(2)), процесс
      создаётся
      в том же
      пространстве
      имён PID, что и
      вызывающий
      процесс.
      Этот флаг
      предназначен
      для
      реализации
      контейнеров.
  
  - Дополнительную
      информацию
      о
      пространствах
      имён PID
      смотрите в
      namespaces(7) и pid_namespaces(7).
- Только
      привилегированный
      процесс
      (CAP_SYS_ADMIN) может
      использовать
      CLONE_NEWPID. Этот
      флаг
      нельзя
      указывать
      вместе с
      CLONE_THREAD или CLONE_PARENT.
  - CLONE_NEWUSER
- (Впервые
      этот флаг
      приобрёл
      значение
      для clone() в Linux 2.6.23,
      текущая
      семантика
      clone()
      появилась
      в Linux 3.5, а
      оставшиеся
      части,
      делающие
      пространства
      имён
      пользователя
      полностью
      работоспособными,
      включены в
      Linux 3.8.)
  
  - Если задан
      флаг CLONE_NEWUSER, то
      процесс
      создаётся
      в новом
      пространстве
      имён
      пользователя.
      Если флаг
      не
      установлен,
      то (как и в
      fork(2)), процесс
      создаётся
      в том же
      пространстве
      имён
      пользователя,
      что и
      вызывающий
      процесс.
- До Linux 3.8, для
      использования
      CLONE_NEWUSER у
      вызывающего
      требовалось
      три
      мандата:
      CAP_SYS_ADMIN, CAP_SETUID и CAP_SETGID.
      Начиная с Linux
      3.8, для
      создания
      пространства
      имён
      пользователя
      никаких
      привилегий
      не
      требуется.
- Этот флаг
      нельзя
      указывать
      вместе с
      CLONE_THREAD или CLONE_PARENT.
      По
      соображениям
      безопасности,
      CLONE_NEWUSER нельзя
      указывать
      вместе с
    CLONE_FS.
- Дополнительную
      информацию
      о
      пространствах
      имён
      пользователя
      смотрите в
      namespaces(7) и user_namespaces(7).
  - CLONE_NEWUTS
    (начиная с Linux
    2.6.19)
- Если задан
      флаг CLONE_NEWUTS, то
      процесс
      создаётся
      в новом
      пространстве
      имён UTS, чьи
      идентификаторы
      инициализируются
      копией
      идентификаторов
      из
      пространства
      имён UTS
      вызывающего
      процесса.
      Если флаг
      не указан,
      то (как и в
      fork(2)), процесс
      создаётся
      в том же
      пространстве
      имён UTS что и
      вызывающий
      процесс.
      Этот флаг
      предназначен
      для
      реализации
      контейнеров.
  
  - Пространство
      имён UTS — это
      набор
      идентификаторов,
      возвращаемых
      uname(2); помимо
      остальных,
      сюда
      включены
      доменное
      имя и имя
      узла,
      которые
      изменить с
      помощью
      setdomainname(2) и sethostname(2),
      соответственно.
      Изменившиеся
      идентификаторы
      в
      пространстве
      имён UTS
      видимы
      всем
      остальным
      процессам
      в том же
      пространстве
      имён, но не
      видимы
      процессам
      из других
      пространств
      имён UTS.
- Только
      привилегированный
      процесс
      (CAP_SYS_ADMIN) может
      использовать
      CLONE_NEWUTS.
- Дополнительную
      информацию
      о
      пространствах
      имён UTS
      смотрите в
      namespaces(7).
  - CLONE_PARENT
    (начиная с Linux
    2.3.12)
- Если задан
      флаг CLONE_PARENT, то
      родитель
      нового
      потомка
      (возвращаемый
      getppid(2)) будет
      таким же
      как и у
      вызывающего
      процесса.
  
  - Если флаг
      CLONE_PARENT не
      задан, то
      (как и в fork(2))
      родителем
      будет
      вызывающий
      процесс.
- Заметим,
      что это тот
      родительский
      процесс,
      который
      возвращается
      вызовом
      getppid(2), и
      которому
      приходит
      сигнал
      когда
      потомок
      завершается,
      так что
      если
      указан
      флаг CLONE_PARENT, то
      сигнал
      будет
      посылаться
      родителю
      вызывающего
      процесса, а
      не самому
      вызывающему
      процессу.
  - CLONE_PARENT_SETTID
    (начиная с Linux
    2.5.49)
- Сохранить
      ID нити
      потомка,
      расположенный
      в ptid в
      памяти
      родителя (в
      Linux 2.5.32-2.5.48 для
      этого
      использовался
      флаг CLONE_SETTID).
      Операция
      сохранения
      завершается
      до
      возврата
      управления
      из clone() в
      пользовательское
      пространство.
- CLONE_PID
    (в Linux 2.0 по 2.5.15)
- Если задан
      флаг CLONE_PID, то
      процесс-потомок
      создаётся
      с таким же
      идентификатором
      процесса
      как у
      вызывающего
      процесса.
      Это хорошо
      для
      ковыряния
      в системе,
      но не более
      того.
      Начиная с 2.3.21
      этот флаг
      может быть
      указан
      только у
      процесса
      загрузки
      системы (PID 0).
      Флаг
      полностью
      удалён из
      исходного
      кода в Linux 2.5.16.
      Начиная с
      этой
      версии,
      ядро
      просто
      игнорирует
      этот бит,
      если он
      установлен
      в flags.
- CLONE_PTRACE
    (начиная с Linux
    2.2)
- Если задан
      флаг CLONE_PTRACE и
      вызывающий
      процесс
      находится
      в режиме
      трассировки,
      то
      процесс-потомок
      также
      будет
      работать в
      режиме
      трассировки
      (см. ptrace(2)).
- CLONE_SETTLS
    (начиная с Linux
    2.5.32)
- Дескриптор
      TLS
      (локальная
      память
      нитей)
      помещается
      в newtls.
  
  - Назначение
      newtls и его
      влияние на
      результат
      зависит от
      архитектуры.
      На x86 newtls
      рассматривается
      как struct user_desc *
      (смотрите
      set_thread_area(2)). На x86_64
      это новое
      значение
      будет
      присвоено
      базовому
      регистру %fs
      (смотрите
      описание
      ARCH_SET_FS в arch_prctl(2)). На
      архитектурах
      с
      отдельным
      регистром
      для TLS это
      новое
      значение
      помещается
      в этот
      регистр.
  - CLONE_SIGHAND
    (начиная с Linux
    2.0)
- Если задан
      флаг CLONE_SIGHAND, то
      вызывающий
      процесс и
      процесс-потомок
      используют
      одну и ту
      же таблицу
      обработчиков
      сигналов.
      Если
      вызывающий
      процесс
      или
      процесс-потомок
      вызывают
      sigaction(2) для
      изменения
      поведения
      при
      получении
      сигнала, то
      это
      поведение
      изменяется
      также и в
      другом
      процессе.
      Однако,
      вызывающий
      процесс и
      процесс-потомок
      имеют
      различные
      маски
      сигналов и
      списки
      ожидающих
      обработки
      сигналов.
      Так, один
      из них
      может
      блокировать
      или
      деблокировать
      сигналы,
      используя
      sigprocmask(2), и это не
      будет
      влиять на
      другой
      процесс.
  
  - Если флаг
      CLONE_SIGHAND не
      указан, то
      процесс-потомок
      наследует
      копию
      обработчиков
      событий
      вызывающего
      процесса,
      снятую на
      момент
      вызова clone().
      Вызовы sigaction(2),
      выполняемые
      позже
      одним из
      процессов,
      не
      оказывают
      влияния на
      другой
      процесс.
- Начиная с Linux
      2.6.0, аргумент
      flags должен
      также
      включать
      CLONE_VM, если
      указан
      флаг CLONE_SIGHAND
  - CLONE_STOPPED
    (начиная с Linux
    2.6.0)
- Если
      указан
      флаг CLONE_STOPPED, то
      после
      создания
      потомок
      перейдёт в
      состояние
      останова
      (как если
      бы ему
      послали
      сигнал SIGSTOP), и
      начнёт
      работу по
      сигналу
    SIGCONT.
  
  - Этот флаг
      устарел
      начиная с Linux
      2.6.25 и был
      удалён в Linux
      2.6.38. Начиная с
      этой
      версии,
      ядро
      просто
      игнорирует
      его без
      ошибки.
      Начиная с Linux
      4.6
      используемый
      под него
      бит
      используется
      для флага
      CLONE_NEWCGROUP.
  - CLONE_SYSVSEM
    (начиная с Linux
    2.5.10)
- Если
      указан
      флаг CLONE_SYSVSEM, то
      потомок и
      вызывающий
      процесс
      будут
      иметь
      общий
      единый
      список
      значений
      регулировки
      семафоров
      System V (semadj)
      (смотрите
      semop(2)). В этом
      случае
      общий
      список
      накапливает
      значения
      semadj из
      общего
      списка
      процессов
      и
      регулировки
      семафоров
      выполняются
      только
      когда
      завершается
      последний
      процесс,
      использующий
      общий
      список (или
      перестаёт
      пользоваться
      общим
      списком с
      помощью
      unshare(2)). Если
      этот флаг
      не указан,
      то потомок
      имеет
      отдельный
      список semadj,
      который
      первоначально
      пуст.
- CLONE_THREAD
    (начиная с Linux
    2.4.0)
- Если
      указан
      флаг CLONE_THREAD, то
      потомок
      размещается
      в той же
      группе
      нитей, что
      и
      вызывающий
      процесс.
      Чтобы
      сделать
      остаток
      обсуждения
      CLONE_THREAD более
      понятным,
      термин
      «нить»
      используется
      для ссылки
      на
      процессы
      внутри
      группы
      нитей.
  
  - Группы
      нитей были
      добавлены
      в Linux 2.4 для
      поддержки
      нитей POSIX,
      описываемых
      как набор
      нитей,
      использующих
      один и тот
      же PID.
      Внутренне
      общий PID —
      это так
      называемый
      идентификатор
      группы
      нитей (TGID).
      Начиная с Linux
      2.4, вызов getpid(2)
      возвращает
      идентификатор
      группы
      нитей
      вызывающего
      процесса.
- Внутри
      группы
      нити можно
      различать
      по их
      (глобальному)
      уникальному
      идентификатору
      нити (TID). TID
      новой нити
      возвращается
      вызывающему
      как
      результат
      clone(), а нить
      может
      узнать
      свой TID с
      помощью
      вызова gettid(2).
- Когда
      вызов clone()
      делается
      без CLONE_THREAD, то
      получаемая
      нить
      помещается
      в новую
      группу
      нитей, чей TGID
      совпадает
      с TID нити. Эта
      нить будет
      лидером
      новой
      группы
      нитей.
- Новая нить,
      созданная
      с CLONE_THREAD, имеет
      тот же
      родительский
      процесс
      что и
      вызвавший
      clone() (т.е., как
      CLONE_PARENT),
      поэтому
      при вызове
      getppid(2)
      возвращается
      одинаковое
      значение
      для всех
      нитей в
      группе
      нитей.
      Когда нить
      CLONE_THREAD
      завершается,
      нити,
      создавшей
      её с
      помощью clone(),
      не
      посылается
      сигнал SIGCHLD
      (или другой
      сигнал
      завершения);
      состояние
      такой нити
      нельзя
      получить с
      помощью wait(2).
      Про нить
      говорят,
      что она
      отсоединена
      (detached).
- После
      завершения
      работы
      всех нитей
      в группе
      нитей
      родительскому
      процессу
      группы
      нитей
      посылается
      сигнал SIGCHLD
      (или другой
      завершающий
      сигнал).
- Если в
      любой из
      нитей
      группы
      нитей
      выполняется
      вызов execve(2),
      то все нити
      отличные
      от лидера
      группы
      нитей,
      завершаются
      и
      выполняется
      новая
      программы
      в лидере
      группы
      нитей.
- Если одна
      из нитей
      группы
      нитей
      создаёт
      потомка с
      помощью fork(2),
      то любая
      нить
      группы
      может
      вызвать wait(2)
      для
      ожидания
      этого
      потомка.
- Начиная с Linux
      2.5.35, аргумент
      flags должен
      также
      включать
      CLONE_SIGHAND, если
      указан
      флаг CLONE_THREAD
      (также
      заметим,
      что
      начиная с Linux
      2.6.0, для CLONE_SIGHAND
      также
      требуется
      включать
      CLONE_VM).
- Расположение
      и действия
      сигналов
      распространяются
      на весь
      процесс:
      если
      необработанный
      сигнал
      доставляется
      нити, то
      это влияет
      (завершение,
      остановка,
      продолжение,
      игнорирование)
      на все
      члены
      группы
      нитей.
- Каждая
      нить имеет
      свою маску
      сигналов,
      задаваемую
      sigprocmask(2).
- Сигнал
      может быть
      направлен
      процессу и
      направлен
      нити. Целью
      сигнала,
      направленного
      процессу,
      является
      группа
      нитей (т. е., TGID),
      и он
      доставляется
      произвольно
      выбранной
      нити среди
      неблокирующих
      сигнал.
      Сигнал
      может быть
      направлен
      процессу
      из ядра по
      причинам,
      не
      относящимся
      к
      аппаратному
      исключению,
      или быть
      послан с
      помощью kill(2)
      или sigqueue(3).
      Целью
      сигнала,
      направленного
      нити,
      является
      определённая
      (т. е.,
      указанная
      в адресе
      назначения)
      нить.
      Сигнал
      может быть
      направлен
      нити
      вызовом tgkill(2)
      или pthread_sigqueue(3),
      или если
      при работе
      нити
      возникло
      аппаратное
      исключение
      при
      выполнении
      ей
      языковой
      инструкции
      (например,
      при
      доступе к
      памяти по
      неправильному
      адресу
      возникает
      SIGSEGV, а
      исключение
      в блоке
      выполнения
      инструкций
      с
      плавающей
      запятой
      приводит к
      SIGFPE).
- Вызов sigpending(2)
      возвращает
      набор
      сигналов,
      который
      представляет
      собой
      объединение
      ожидающих
      сигналов,
      направленных
      процессу, и
      сигналов,
      которые
      ожидает
      вызывающая
      нить.
- Если
      сигнал,
      оправленный
      процессу,
      доставляется
      группе
      нитей и у
      группы
      нитей
      установлен
      обработчик
      сигнала, то
      обработчик
      будет
      вызван
      только
      один раз в
      произвольно
      выбранном
      члене
      группы
      нитей,
      который не
      блокирует
      сигнал.
      Если
      несколько
      нитей в
      группе
      ждут
      приёма
      того же
      сигнала с
      помощью
      sigwaitinfo(2), то ядро
      произвольно
      выберет
      одну из
      этих нитей
      для приёма
      сигнала.
  - CLONE_UNTRACED
    (начиная с Linux
    2.5.46)
- Если
      указан
      флаг CLONE_UNTRACED, то
      выполняющий
      трассировку
      процесс не
      сможет
      указать
      CLONE_PTRACE на этом
      процессе-потомке.
- CLONE_VFORK
    (начиная с Linux
    2.2)
- Если
      указан
      флаг CLONE_VFORK, то
      выполнение
      вызывающего
      процесса
      приостанавливается
      до тех пор,
      пока
      потомок не
      освободит
      ресурсы
      виртуальной
      памяти с
      помощь
      вызова execve(2)
      или _exit(2) (как
      с vfork(2)).
  
  - Если флаг
      CLONE_VFORK не
      указан, то
      вызывающий
      процесс и
      потомок
      доступны
      для
      планирования
      после
      вызова, и
      приложение
      не должно
      полагаться
      на то, что
      выполнение
      производится
      в каком-то
      определённом
      порядке.
  - CLONE_VM
    (начиная с Linux
    2.0)
- Если задан
      флаг CLONE_VM, то
      вызывающий
      и дочерний
      процесс
      работают в
      одном
      пространстве
      памяти. В
      частности,
      запись в
      память
      одним
      процессом
      видна
      другому.
      Кроме того,
      выполнение
      отображения
      или снятия
      отображения
      в память,
      выполняемая
      с помощью
      mmap(2) или munmap(2),
      одним
      процессом,
      влияет на
      другой.
  
  - Если флаг
      CLONE_VM не
      установлен,
      то
      дочерний
      процесс
      выполняется
      в
      отдельной
      копии
      пространства
      памяти
      вызывающего
      процесс с
      момента clone().
      Запись в
      память или
      отображение/снятие
      отображения
      файла,
      выполняемое
      одним
      процессом,
      не влияет
      на другой
      (как с fork(2)).
ЗАМЕЧАНИЯ
Заметим,
    что
    обёрточная
    функция glibc
    clone() делает
    некоторые
    изменения
    в памяти, на
    которую
    указывает
    child_stack
    (изменения
    требуются
    для
    правильной
    настройки
    стека в
    потомке)
    перед
    запуском
    системного
    вызова clone().
    Поэтому в
    случаях,
    когда clone()
    используется
    для
    рекурсивного
    создания
    потомков,
    не
    используйте
    буфер
    стека
    родителя в
    качестве
    стека
    потомка.
Отличия
  между
  библиотекой
  C и ядром
Системный
    вызов clone()
    больше
    похож на fork(2)
    в том плане,
    что
    выполнение
    в потомке
    продолжается
    от места
    вызова.
    Таким
    образом,
    аргументы
    fn и arg
    обёрточной
    функции clone()
    отсутствуют.
Другим
    отличием
    системного
    вызова clone()
    является
    то, что
    аргумент
    child_stack может
    быть равен
    NULL, если
    потомок
    использует
    копию
    родительского
    стека
    (копирование-при-записи
    гарантирует,
    что
    потомок
    получит
    отдельные
    копии
    страниц
    стека, если
    один из
    процессов
    изменит
    стек). В этом
    случае для
    правильной
    работы не
    должен
    использоваться
    флаг CLONE_VM
    (если
    потомок
    использует
    родительскую
    память
    из-за
    указания
    CLONE_VM, то
    создания
    копии при
    копировании-при-записи
    не
    происходит
    и, вероятно,
    это вызове
    хаос).
В
    системном
    вызове
    также
    другой
    порядок
    аргументов,
    он
    различен у
    разных
    архитектур
    (описан
    далее).
Интерфейс
    внутреннего
    системного
    вызова на x86-64
    и
    некоторых
    других
    архитектурах
    (включая sh, tile, ia-64
    и alpha):
  
long clone(unsigned long flags, void *child_stack,
           int *ptid, int *ctid,
           unsigned long newtls);
На x86-32 и
    некоторых
    других
    распространённых
    архитектурах
    (включая score, ARM, ARM
    64, PA-RISC, arc, Power PC, xtensa и MIPS)
    порядок
    последних
    двух
    аргументов
    обратный:
  
long clone(unsigned long flags, void *child_stack,
          int *ptid, unsigned long newtls,
          int *ctid);
На
    архитектурах
    cris и s390 порядок
    первых
    двух
    аргументов
    обратный:
  
long clone(void *child_stack, unsigned long flags,
           int *ptid, int *ctid,
           unsigned long newtls);
На
    архитектуре
    microblaze есть
    дополнительный
    аргумент:
  
long clone(unsigned long flags, void *child_stack,
           int stack_size,         /* Size of stack */
           int *ptid, int *ctid,
           unsigned long newtls);
Соглашение
    по
    передаче
    аргументов
    на blackfin, m68k и sparc
    отличается
    от
    описанного
    выше.
    Подробности
    смотрите в
    исходном
    коде ядра (и
    glibc).
На ia64
    используется
    другой
    интерфейс:
  
int __clone2(int (*fn)(void *), 
             void *child_stack_base, size_t stack_size,
             int flags, void *arg, ... 
          /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );
Прототип,
    показанный
    выше,
    относится
    к
    обёрточной
    функции glibc;
    прототип
    системного
    вызова
    можно
    описать
    следующим
    образом
    (одинаков с
    прототипом
    clone() на microblaze):
  
long clone2(unsigned long flags, void *child_stack_base,
            int stack_size,         /* Size of stack */
            int *ptid, int *ctid,
            unsigned long tls);
Системный
    вызов __clone2()
    работает
    также как и
    clone() за
    исключением
    того, что
    child_stack_base
    указывает
    на самый
    нижний
    адрес
    области
    стека
    потомка, и в
    stack_size
    задаётся
    размер
    стека,
    указываемого
    в child_stack_base.
В Linux 2.4 и
    более
    ранних clone()
    не
    принимал
    аргументов
    ptid, tls и ctid.
ВОЗВРАЩАЕМОЕ
  ЗНАЧЕНИЕ
При
    успешном
    выполнении
    в
    вызывающую
    исполняемую
    нить
    возвращается
    ID нити
    дочернего
    процесса.
    Иначе в
    контекст
    вызывающего
    возвращается
    -1, дочерний
    процесс не
    создаётся
    и errno
    устанавливается
    в
    соответствующее
    значение.
ОШИБКИ
  - EAGAIN
- Уже
      выполняется
      максимальное
      количество
      процессов;
      смотрите
      fork(2).
- EINVAL
- Указан
      флаг CLONE_SIGHAND, но
      нет CLONE_VM
      (начиная с Linux
      2.6.0).
- EINVAL
- Указан
      флаг CLONE_THREAD, но
      нет CLONE_SIGHAND
      (начиная с Linux
      2.5.35).
- EINVAL
- Указан
      флаг CLONE_THREAD, но
      текущий
      процесс до
      этого
      вызвал unshare(2)
      с флагом
      CLONE_NEWPID или
      использовал
      setns(2) для
      своего
      отсоединения
      от
      пространства
      имён PID.
- EINVAL
- Указаны
      оба флага,
      CLONE_FS и CLONE_NEWNS, в flags.
- EINVAL
    (начиная с Linux
    3.9)
- Указаны
      оба флага,
      CLONE_NEWUSER и CLONE_FS, в flags.
- EINVAL
- Указаны
      оба флага,
      CLONE_NEWIPC и CLONE_SYSVSEM, в
    flags.
- EINVAL
- Указан
      один или
      оба флага,
      CLONE_NEWPID или CLONE_NEWUSER,
      и один или
      оба флага,
      CLONE_THREAD или CLONE_PARENT, в
      flags.
- EINVAL
- Возвращается
      обёрточной
      функцией glibc
      clone(), если fn
      или child_stack
      равны NULL.
- EINVAL
- Указан
      флаг CLONE_NEWIPC в
      flags, но ядро
      собрано
      без
      параметров
      CONFIG_SYSVIPC и CONFIG_IPC_NS.
- EINVAL
- Указан
      флаг CLONE_NEWNET в
      flags, но ядро
      собрано
      без
      параметра
      CONFIG_NET_NS.
- EINVAL
- Указан
      флаг CLONE_NEWPID в
      flags, но ядро
      собрано
      без
      параметра
      CONFIG_PID_NS.
- EINVAL
- Указан
      флаг CLONE_NEWUSER в
      flags, но ядро
      собрано
      без
      параметра
      CONFIG_USER_NS.
- EINVAL
- Указан
      флаг CLONE_NEWUTS в
      flags, но ядро
      собрано
      без
      параметра
      CONFIG_UTS_NS.
- EINVAL
- Значение
      child_stack не
      выровнено
      по нужной
      границе
      для этой
      архитектуры.
      Например,
      на aarch64 child_stack
      должно
      быть
      кратно 16.
- ENOMEM
- Не удалось
      выделить
      достаточно
      памяти для
      структуры
      задач
      потомка
      или
      скопировать
      необходимые
      части
      контекста
      вызывающего.
- ENOSPC
    (начиная с Linux
    3.7)
- В флагах
      указан CLONE_NEWPID,
      но вызов
      привёл бы к
      превышению
      ограничения
      на
      количество
      вложенных
      имён PID;
      смотрите
      pid_namespaces(7).
- ENOSPC
    (начиная с Linux
    4.9; до этого
    EUSERS)
- Флаг CLONE_NEWUSER
      указан в flags,
      и вызов
      привёл бы к
      превышению
      ограничения
      на
      количество
      вложенных
      пользовательских
      пространств
      имён.
      Смотрите
      user_namespaces(7).
  
  - В этом
      случае в Linux 3.11
      по Linux 4.8
      возвращалась
      ошибка EUSERS.
  - ENOSPC
    (начиная с Linux
    4.9)
- Одним из
      значений в
      flags
      задаётся
      создание
      нового
      пространства
      пространства
      имён
      пользователя,
      но это
      превысило
      бы
      ограничение,
      определённое
      в
      соответствующем
      файле в
      каталоге
      /proc/sys/user.
      Дополнительную
      информацию
      смотрите в
      namespaces(7).
- EPERM
- Указан
      флаг CLONE_NEWCGROUP,
      CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWNS,
      CLONE_NEWPID или CLONE_NEWUTS,
      но процесс
      не имеет
      достаточно
      прав (нет
      мандата
      CAP_SYS_ADMIN).
- EPERM
- Указан
      флаг CLONE_PID, но ID
      процесса
      не равен 0
      (эта ошибка
      возникает
      только в Linux 2.5.15
      и старее).
- EPERM
- Флаг CLONE_NEWUSER
      указан в flags,
      но
      эффективный
      пользовательский
      ID или
      эффективный
      ID группы
      вызывающего
      не
      отображён
      в
      родительское
      пространство
      имён
      (смотрите
      user_namespaces(7)).
- EPERM
    (начиная с Linux
    3.9)
- В flags был
      указан
      флаг CLONE_NEWUSER и
      вызывающий
      выполняется
      в
      окружении
      chroot (т. е.
      корневой
      каталог
      вызывающего
      не
      совпадает
      с корневым
      каталогом
      пространства
      имён
      монтирования,
      в котором
      он
      находится).
- ERESTARTNOINTR
    (начиная с Linux
    2.6.17)
- Системный
      вызов был
      прерван
      сигналом и
      перезапущен
      (может быть
      замечено
      только при
      трассировке).
- EUSERS (с
    Linux 3.11 по Linux 4.8)
- Флаг CLONE_NEWUSER
      указан в flags,
      и вызов
      привёл бы к
      превышению
      ограничения
      на
      количество
      вложенных
      пользовательских
      пространств
      имён.
      Смотрите
      описание
      ошибки ENOSPC,
      представленное
      выше.
СООТВЕТСТВИЕ
  СТАНДАРТАМ
Вызов clone()
    есть
    только в Linux и
    не должен
    использоваться
    в
    переносимых
    программах.
ЗАМЕЧАНИЯ
Системный
    вызов kcmp(2)
    можно
    использовать
    для
    проверки
    того, что
    два
    процесса
    совместно
    используют
    различные
    ресурсы,
    такие как
    таблицу
    файловых
    дескрипторов,
    семафор System V
    для отмены
    операций
    или
    виртуальное
    адресное
    пространство.
Обработчики,
    зарегистрированные
    с помощью
    pthread_atfork(3), не
    выполняются
    во время
    вызова clone().
Для ядер
    версий Linux 2.4.x,
    флаг CLONE_THREAD не
    делает
    родителем
    новой нити
    того же
    родителя
    что и у
    вызывающего
    процесса.
    Однако для
    ядер
    версий 2.4.7-2.4.18
    флаг CLONE_THREAD
    неявно
    подразумевает
    флаг CLONE_PARENT
    (как в ядре Linux
    2.6.0 и новее).
Некоторое
    время
    существовал
    флаг CLONE_DETACHED
    (начиная с 2.5.32):
    родитель
    не хочет
    получать
    сигнал
    завершения
    потомка. В Linux
    2.6.2
    необходимость
    указывать
    этот флаг
    вместе с
    CLONE_THREAD отпала.
    Этот флаг
    ещё
    определён,
    но не
    оказывает
    никакого
    действия.
На
    архитектуре
    i386 clone() не
    должен
    вызываться
    через vsyscall, а
    запускаться
    явно с
    помощью int
  $0x80.
ДЕФЕКТЫ
Версии
    библиотеки
    GNU C с 2.3.4 и по 2.24
    включительно
    содержат
    обёрточную
    функцию
    для getpid(2),
    которая
    выполняет
    кэширование
    значений PID.
    Это
    кэширование
    основано
    на
    поддержке
    обёрточной
    функции glibc
    для clone(), но
    ограничения
    в
    реализации
    полагаются,
    что кэш в
    некоторых
    случаях не
    устаревает
    до
    определённой
    даты. В
    частности,
    если
    сигнал был
    доставлен
    потомку
    сразу
    после
    вызова clone(),
    то вызов getpid(2)
    обработчике
    сигнала
    может
    вернуть PID
    вызывающего
    процесса
    («родителя»),
    если у
    обёртки clone
    пока не
    было шанса
    изменить
    кэш PID в
    потомке (в
    этом
    описании
    игнорируется
    случай, где
    потомок
    был создал
    с
    использованием
    CLONE_THREAD, когда
    getpid(2) должен
    вернуть то
    же
    значение в
    потомок и в
    процесс,
    вызывавший
    clone(), так как
    вызывающий
    и потомок
    находятся
    в одной
    группе
    нитей.
    Проблема
    просроченного
    кэша также
    не
    возникает,
    если в
    аргументе
    flags
    содержится
    CLONE_VM). Чтобы
    узнать
    правду,
    было
    иногда
    необходимо
    использовать
    такой код:
  
#include <syscall.h>
pid_t mypid;
mypid = syscall(SYS_getpid);
Из-за
    проблем
    просроченного
    кэша (stale-cache), а
    также
    других,
    упомянутых
    в getpid(2),
    свойство
    кэширования
    PID было
    удалено в glibc
    2.25.
ПРИМЕР
Следующая
    программа
    демонстрирует
    использование
    clone() для
    создания
    дочернего
    процесса,
    который
    выполняется
    в
    отдельном
    пространстве
    имён UTS.
    Потомок
    изменяет
    имя узла в
    своём
    пространстве
    имён UTS. И
    предок и
    потомок
    затем
    выводят
    системное
    имя узла,
    чтобы
    можно было
    убедиться
    в
    неодинаковости
    пространств
    имён.
    Пример
    использования
    этой
    программы
    смотрите в
    setns(2).
Исходный
  код
  программы
#define _GNU_SOURCE
#include <sys/wait.h>
#include <sys/utsname.h>
#include <sched.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                        } while (0)
static int              /* Начало функции клонированного
                           потомка */
childFunc(void *arg)
{
    struct utsname uts;
    /* Изменяем имя узла в пространстве имён UTS потомка */
    if (sethostname(arg, strlen(arg)) == -1)
        errExit("sethostname");
    /* Получаем и показывает имя узла */
    if (uname(&uts) == -1)
        errExit("uname");
    printf("uts.nodename in child:  %s\n", uts.nodename);
    /* Перед сном оставим пространство имён открытым.
       Это позволяет поэкспериментировать — например, другой
       процесс может подключиться к пространству имён. */
    sleep(200);
    return 0;           /* Завершение работы потомка */
}
#define STACK_SIZE (1024 * 1024)    /* Размер стека клонированного
                                       потомка */
int
main(int argc, char *argv[])
{
    char *stack;                    /* Начало буфера стека */
    char *stackTop;                 /* Конец буфера стека */
    pid_t pid;
    struct utsname uts;
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <child-hostname>\n", argv[0]);
        exit(EXIT_SUCCESS);
    }
    /* Выделение стека для потомка */
    stack = malloc(STACK_SIZE);
    if (stack == NULL)
        errExit("malloc");
    stackTop = stack + STACK_SIZE;  /* Считаем, что стек растёт вниз */
    /* Создаём потомка с собственным пространством имён UTS;
       потомок начинает выполнение с childFunc() */
    pid = clone(childFunc, stackTop, CLONE_NEWUTS | SIGCHLD, argv[1]);
    if (pid == -1)
        errExit("clone");
    printf("clone() returned %ld\n", (long) pid);
    /* Предок попадает сюда */
    sleep(1);           /* Даём время потомку изменить своё имя узла */
    /* Показываем имя узла в пространстве имён UTS предка. Оно будет
       отличаться от имени узла в пространстве имён UTS потомка. */
    if (uname(&uts) == -1)
        errExit("uname");
    printf("uts.nodename in parent: %s\n", uts.nodename);
    if (waitpid(pid, NULL, 0) == -1)    /* Ждём потомка */
        errExit("waitpid");
    printf("child has terminated\n");
    exit(EXIT_SUCCESS);
}
СМОТРИТЕ
  ТАКЖЕ
fork(2), futex(2), getpid(2),
    gettid(2), kcmp(2), set_thread_area(2),
    set_tid_address(2), setns(2), tkill(2),
    unshare(2), wait(2), capabilities(7),
    namespaces(7), pthreads(7)