Тот факт, что направление роста стека зависит от архитектуры, является концептуальным недостатком вызова clone(). Архитектура Intel IA-64 предоставляет улучшенный программный интерфейс клонирования в виде вызова clone2(). Он описывает диапазон дочернего стека таким образом, что направление его роста не имеет значения, поскольку передается сразу два адреса — начальный и конечный. Подробности ищите на справочной странице.
Аргумент flags вызова clone() служит сразу двум целям. Во-первых, его нижний байт содержит
Вызовы fork() и vfork() не позволяют выбрать сигнал завершения; это всегда будет SIGCHLD.
Оставшиеся байты аргумента flags отводятся под битовую маску, которая определяет поведение вызова clone(). Ее значения собраны в табл. 28.2 и подробно описаны в подразделе 28.2.1.
Таблица 28.2. Значения битовой маски flags вызова clone()
Флаг — Действие
CLONE_CHILD_CLEARTID — Очищает ctid, когда потомок вызывает exec() или _exit() (начиная с 2.6) (здесь и далее в скобках версия Linux)
CLONE_CHILD_SETTID — Записывает идентификатор дочернего потока в ctid (начиная с 2.6)
CLONE_FILES — Родитель и потомок разделяют таблицу дескрипторов открытых файлов
CLONE_FS — Родитель и потомок разделяют атрибуты, относящиеся к файловой системе
CLONE_IO — Потомок получает доступ к контексту ввода/вывода родителя (начиная с 2.6.25)
CLONE_NEWIPC — Потомок получает новое пространство имен в System V IPC (начиная с 2.6.19)
CLONE_NEWNET — Потомок получает сетевое пространство имен (начиная с 2.4.24)
CLONE_NEWNS — Потомок получает копию родительского пространства имен файловой системы (2.4.19)
CLONE_NEWPID — Потомок получает новое пространство имен с идентификаторами процессов (начиная с 2.6.19)
CLONE_NEWUSER — Потомок получает новое пространство имен с идентификаторами пользователей (начиная с 2.6.23)
CLONE_NEWUTS — Потомок получает новое пространство имен UTS (utsname()) (начиная с 2.6.19)
CLONE_PARENT — Делает родителя потомка тождественным вызывающему процессу родителя (начиная с 2.4)
CLONE_PARENT_SETTID — Записывает идентификатор дочернего потока в ptid (начиная с 2.6)
CLONE_PID — Устаревший флаг, который используется только процессом загрузки системы (до 2.4)
CLONE_PTRACE — Трассирует потомка, если трассируется его родитель
CLONE_SETTLS — tls описывает для потомка хранилище на уровне потока выполнения (начиная с 2.6)
CLONE_SIGHAND — Родитель и потомок разделяют действия сигналов
CLONE_SYSVSEM — Родитель и потомок разделяют значения отмены семафоров (начиная с 2.6)
CLONE_THREAD — Помещает потомка в одну группу потоков выполнения с его родителем (начиная с 2.4)
CLONE_UNTRACED — Не позволяет применить к потомку значение CLONE_PTRACE (начиная с 2.6)
CLONE_VFORK — Родитель приостанавливает работу, пока потомок не сделает вызов exec() или _exit()
CLONE_VM — Родитель и потомок разделяют виртуальную память
Оставшиеся аргументы вызова clone() — ptid, tls и ctid. Они относятся к реализации потока выполнения — в частности, к использованию его идентификатора и локального хранилища. Мы рассмотрим применение этих аргументов, когда будем описывать значения битовой маски flags в подразделе 28.2.1 (в версиях Linux до 2.4 включительно эти три аргумента отсутствуют в вызове clone(); их специально добавили в Linux 2.6 для поддержки библиотеки потоков POSIX NPTL).
В листинге 28.3 показан простой пример использования вызова clone() для создания дочернего процесса. Главная программа делает следующее.
• Открывает файловый дескриптор (для /dev/null), который будет закрыт потомком
• Присваивает аргументу flags вызова clone() значение CLONE_FILES
• Выделяет стек для потомка
• Если значение CHILD_SIG не равно 0 или SIGCHLD, оно будет игнорироваться в случае завершения процесса по сигналу. Мы не игнорируем SIGCHLD, поскольку это помешало бы нам ждать потомка для получения его статуса.
• Вызывает clone() для создания потомка
• Ждет завершения работы потомка
• Проверяет, открыт ли все еще файловый дескриптор (созданный на шаге