Linux repositories inspector

posix_spawn(3) - Russkiy

GNU
2019-03-06
Aliases: posix_spawnp(3), posix_spawnp(3), posix_spawnp(3)

man-pages-ru

Russian man pages from the Linux Documentation Project

manpages-dev

Manual pages about using GNU/Linux for development

man-pages

Linux kernel and C library user-space interface documentation

ИМЯ

posix_spawn, posix_spawnp - порождает процесс

ОБЗОР

#include <spawn.h>

int posix_spawn(pid_t *pid, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[]);
int posix_spawnp(pid_t *pid, const char *file, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[]);

ОПИСАНИЕ

Функции posix_spawn() и posix_spawnp() используются для создания новых дочерних процессов, которые выполняют указываемый файл. Эти функции были определены в POSIX для стандартизации метода создания новых процессов на машинах, у которых нет возможности поддержки системного вызова fork(2). К таким машинах, обычно, относятся встраиваемые системы без поддержки MMU.
Функции posix_spawn() и posix_spawnp() предоставляют комбинацию возможностей fork(2) и exec(3) с некоторыми необязательными обслуживающими действиями в дочернем процессе перед exec(3). Эти функции не служат заменой системных вызовов fork(2) и execve(2). Фактически, они предоставляют только часть функций системных вызовов.
Единственным отличием между posix_spawnp() и posix_spawnp() является способ, которым в них указывается исполняемый дочерним процессом файл. В posix_spawn() исполняемый файл задаётся в виде пути (которое может быть абсолютным или относительным). В posix_spawnp() исполняемый файл задаётся в виде имени файла; система ищет этот файл в списке каталогов, указанных в PATH (также, как это делает execvp(3)). Кроме данного отличия далее на этой странице всё описание posix_spawn() также относится и к posix_spawnp().
Остальные аргументы функций:
* Аргумент pid указывает на буфер, в котором возвращается ID нового дочернего процесса.
* Аргумент file_actions указывает на объект файловых действий при создании, в котором задаются действия с файлом, выполняемые в потомке между шагами fork(2) и exec(3). Данный объект инициализируется и заполняется перед вызовом posix_spawn() с помощью функций posix_spawn_file_actions_init(3) и posix_spawn_file_actions_*().
* Аргумент attrp указывает на объект атрибутов, в котором задаются различные атрибуты создаваемого дочернего процесса. Данный объект инициализируется и заполняется перед вызовом posix_spawn() с помощью функций posix_spawnattr_init(3) и posix_spawnattr_*().
* В аргументах argv и envp задаётся список аргументов и окружения для программы, выполняемой в дочернем процессе, как для execve(2).
Далее функции описаны в виде трёх ступенчатого процесса: шаг fork(), шаг перед exec() (выполняется в потомке) и шаг exec() (выполняется в потомке).

Шаг fork()

Функция posix_spawn() начинает работу с вызова fork(2) или, возможно, vfork(2) (смотрите ниже).
PID нового дочернего процесса помещается в *pid. После этого функция posix_spawn() возвращает управление родительскому процессу.
Соответственно, родитель может использовать один из системных вызовов, описанных в wait(2), для проверки состояния дочернего процесса. Если потомок завершится с ошибкой в любом из служебных шагов, описанных далее, или возникнет ошибка при выполнении желаемого файла, то он завершит работу с кодом состояния 127.
Дочерний процесс создаётся с помощью vfork(2), а не fork(2) в любом из следующих случаев:
* элемент spawn-flags объекта атрибутов, на который указывает attrp, содержит определённый в GNU флаг POSIX_SPAWN_USEVFORK; или
* file_actions равно NULL и элемент spawn-flags объекта атрибутов, на который указывает attrp, не содержит POSIX_SPAWN_SETSIGMASK, POSIX_SPAWN_SETSIGDEF, POSIX_SPAWN_SETSCHEDPARAM, POSIX_SPAWN_SETSCHEDULER, POSIX_SPAWN_SETPGROUP или POSIX_SPAWN_RESETIDS.
Иначе говоря, vfork(2) используется, если это запросил вызывающий или не нужна очистка в потомке перед выполнением exec(3) запрашиваемого файла.

Шаг перед exec(): служебные действия

Между fork(2) и exec(3) дочерний процесс может выполнить набор служебных действий. Функции posix_spawn() и posix_spawnp() поддерживают маленький, хорошо спроектированный набор системных задач, которые дочерний процесс может выполнить перед запуском исполняемого файла. Эти операции управляются объектом атрибутов, на который указывает attrp и объект файловых действий, на который указывает file_actions. В потомке обработка выполняются в следующей последовательности:
1. Действия с атрибутами процесса: маска сигналов, обработчики сигналов по умолчанию, алгоритм планирования и параметры, ID группы процесса, эффективного пользователя и группы изменяются согласно объекту атрибутов, на который указывает attrp.
2. Файловые действия, указываемые в аргументе file_actions, выполняются в порядке их определения вызовами функций posix_spawn_file_actions_add*().
3. Закрываются файловые дескрипторы, имеющие флаг FD_CLOEXEC.
Все атрибуты процесса-потомка, отличные от атрибутов в объекте, на который указывает attrp и файловые действия в объекте, на который указывает file_actions, будут изменены как если бы потомок создавался с помощью fork(2) и выполнял программу с помощью execve(2).
Действия атрибутов процесса определяются атрибутами объекта, на который указывает attrp. Атрибут spawn-flags (устанавливается с помощью posix_spawnattr_setflags(3)) управляет общими действиями, а остальные атрибуты объекта хранят значения, которые будут использованы в этих действиях.
Влияние флагов, которые могут быть указаны в spawn-flags:
POSIX_SPAWN_SETSIGMASK
Назначить маску сигналов равной набору сигналов, определённой в атрибуте spawn-sigmask объекта, на который указывает attrp. Если не установлен флаг POSIX_SPAWN_SETSIGMASK, то потомок наследует маску сигналов родителя.
POSIX_SPAWN_SETSIGDEF
Сбрасывает обработчики всех сигналов в наборе, заданном в атрибуте spawn-sigdefault объекта, на который указывает attrp, в значения по умолчанию. О том, что происходит с обработчиками сигналов не указанных в атрибуте spawn-sigdefault или когда не указан POSIX_SPAWN_SETSIGDEF, смотрите execve(2).
POSIX_SPAWN_SETSCHEDPARAM
Если этот флаг установлен, а POSIX_SPAWN_SETSCHEDULER нет, то изменяет параметры планирования на значения, указанные в атрибуте spawn-schedparam объекта, на который указывает attrp.
POSIX_SPAWN_SETSCHEDULER
Назначает алгоритм планирования и параметры потомка:
* Алгоритму планирования присваивается значение, указанное в атрибуте spawn-schedpolicy объекта, на который указывает attrp.
* Параметрам планирования присваивается значение, указанное в атрибуте spawn-schedparam объекта, на который указывает attrp (но смотрите ДЕФЕКТЫ).
Если не указаны флаги POSIX_SPAWN_SETSCHEDPARAM и POSIX_SPAWN_SETSCHEDPOLICY, то потомок наследует соответствующие атрибуты планирования от родителя.
POSIX_SPAWN_RESETIDS
Если этот флаг установлен, то сбрасываются эффективный UID и GID в реальный UID и GID родительского процесса. Если флаг не установлен, то потомок сохраняет эффективный UID и GID родителя. В любом случае, если биты прав set-user-ID и set-group-ID включены на исполняемом файле, то это заменяет значения эффективного UID и GID (смотрите execve(2)).
POSIX_SPAWN_SETPGROUP
Назначает группе процесса значение, указанное в атрибуте spawn-pgroup объекта, на который указывает attrp. Если атрибут spawn-pgroup равен 0, то ID группы потомка становится равным его ID процесса. Если флаг POSIX_SPAWN_SETPGROUP не установлен, то потомок наследует ID группы процесса родителя.
Если attrp равно NULL, то выполняются действия по умолчанию, которые описаны выше по каждому флагу.
Аргумент file_actions задаёт последовательность файловых операций, которые выполняются в дочернем процессе после общей обработки, описанной выше, и перед выполнением exec(3). Если file_actions равно NULL, то никаких специальных действий не производится и выполняются стандартные действия exec(3) — файловые дескрипторы, открытые до выполнения exec, остаются открытыми и в новом процессе, за исключением тех, у которых установлен флаг FD_CLOEXEC. Файловые блокировки остаются как были.
Если file_actions не равно NULL, то в нём содержится упорядоченный набор запросов open(2), close(2) и dup2(2) на файлы. Эти запросы добавляются в file_actions с помощью posix_spawn_file_actions_addopen(3), posix_spawn_file_actions_addclose(3) и posix_spawn_file_actions_adddup2(3). Запрашиваемые операции выполняются в порядке их добавления в file_actions.
Если какая-либо обслуживающая операция завершается с ошибкой, (из-за переданных некорректных значений или по другим причинам, из-за которых обработка сигналов, планирование процесса, функции изменения ID группы процесса и операции с файловыми дескрипторами завершается с ошибкой), дочерний процесс завершается с кодом выхода 127.

Шаг exec()

После того как потомок создан (fork) и выполнены все запрошенные шаги до exec, потомок выполняет запуск запрошенного исполняемого файла.
Дочерний процесс берёт своё окружение из аргумента envp, которое рассматривается также как если бы оно передавалось в execve(2). Аргументы созданного процесса выбираются из аргумента argv, который обрабатывается также как для execve(2).

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При успешном завершении posix_spawn() и posix_spawnp() помещают PID дочернего процесса в pid и возвращают 0. Если перед или во время fork(2) возникла ошибка, то потомок не создаётся, содержимое *pid неопределенно и функции возвращают номер ошибки (описано далее).
Даже когда эти функции выполняются без ошибок, дочерний процесс всё ещё может завершиться с ошибкой по многим причинам, касающимся инициализации до exec(). Также, может завершиться ошибкой и exec(3). Во всех этих случаях дочерний процесс завершается с кодом ошибки 127.

ОШИБКИ

Функции posix_spawn() и posix_spawnp() завершаются с ошибкой, только из-за ошибок в используемых вызовах fork(2) и vfork(2); в этих случаях эти функции возвращают номер ошибки, который может быть одним из описанных в fork(2) или vfork(2).
Также, эти функции завершаются с ошибкой если:
ENOSYS Функции не поддерживаются в этой системе.

ВЕРСИИ

Функции posix_spawn() и posix_spawnp() доступны в glibc начиная с версии 2.2.

СООТВЕТСТВИЕ СТАНДАРТАМ

POSIX.1-2001, POSIX.1-2008.

ЗАМЕЧАНИЯ

Обслуживающие действия в потомке управляются объектами, на который указывает attrp (для не файловых действий) и file_actions. В описании POSIX типы данных posix_spawnattr_t и posix_spawn_file_actions_t указываются как объекты, а их элементам не даны имена. Переносимые программы должны инициализировать эти объекты с только помощью функций, определённых в POSIX (другими словами, хотя эти объекты могут быть реализованы как структуры с полями, в переносимых программах нельзя привязываться к такой реализации).
В POSIX не определено вызывать ли обработчики fork, установленные с помощью pthread_atfork(3), при вызове posix_spawn(). В glibc обработчики fork вызываются только, если потомок создан с помощью fork(2).
Не существует функции «posix_fspawn» (т. е., функции типа posix_spawn(), которая вызывала бы fexecve(3) вместо execve(2)). Однако, подобное поведение можно получить указав аргумент path как один из файлов в каталоге /proc/self/fd вызывающего.

ДЕФЕКТЫ

В POSIX.1 указано, что когда в spawn-flags определён POSIX_SPAWN_SETSCHEDULER, флаг POSIX_SPAWN_SETSCHEDPARAM (если есть) игнорируется. Однако до glibc 2.14 вызов posix_spawn() завершался с ошибкой, если POSIX_SPAWN_SETSCHEDULER был указан, а POSIX_SPAWN_SETSCHEDPARAM отсутствовал.

ПРИМЕР

Представленная далее программа показывает использование различных функций программного интерфейса POSIX для создания процессов. Она принимает атрибуты из командной строки, которые позволяют задать файловые действия и атрибуты объектов при создании. В остальных аргументах командной строки задаются имя исполняемого файла и аргументы командной строки для программы, исполняемой в потомке.
Здесь для исполнения в потомке указана команда date(1) и вызов posix_spawn() не использует каких-либо файловых действий и атрибутов объекта.
$ ./a.out date PID потомка: 7634 Tue Feb 1 19:47:50 CEST 2011 Состояние потомка: завершился, состояние=0
Здесь параметром командной строки -c передаётся объект файловых действий, которые закрывают стандартный вывод в потомке. В результате этого date(1) завершается с ошибкой, когда пытается выполнить вывод данных и завершается с кодом состояния 1.
$ ./a.out -c date PID потомка: 7636 date: write error: Bad file descriptor Состояние потомка: завершился, состояние=1
Здесь используется параметр командной строки -s для создания объекта атрибутов, который используется для блокировки всех сигналов (блокируемых) в потомке. В результате этого попытка убить потомка сигналом по умолчанию (т. е., SIGTERM) с помощью kill(1) завершается ошибкой, так как этот сигнал заблокирован. Теперь, чтобы убить потомка, требуется сигнал SIGKILL (SIGKILL невозможно заблокировать).
$ ./a.out -s sleep 60 & [1] 7637 $ PID потомка: 7638
$ kill 7638 $ kill -KILL 7638 $ Состояние потомка: убит по сигналу 9 [1]+ Done ./a.out -s sleep 60
Когда мы пытаемся выполнить в потомке несуществующую команду, exec(3) завершается с ошибкой и потомок завершается с кодом 127.
$ ./a.out xxxxx PID потомка: 10190 Состояние потомка: завершился, состояние=127

Исходный код программы

#include <spawn.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <wait.h> #include <errno.h>
#define errExit(msg) do { perror(msg); \
exit(EXIT_FAILURE); } while (0)
#define errExitEN(en, msg) \
do { errno = en; perror(msg); \
exit(EXIT_FAILURE); } while (0)
char **environ;
int main(int argc, char *argv[]) {
pid_t child_pid;
int s, opt, status;
sigset_t mask;
posix_spawnattr_t attr;
posix_spawnattr_t *attrp;
posix_spawn_file_actions_t file_actions;
posix_spawn_file_actions_t *file_actionsp;
/* разбор параметров командной строки, которые можно использовать
в потомке в качестве объекта атрибутов и файловых действий */
attrp = NULL;
file_actionsp = NULL;
while ((opt = getopt(argc, argv, "sc")) != -1) {
switch (opt) {
case \(aqc\(aq: /* -c: закрыть стандартный вывод в потомке */
/* создаём объект файловых действий и добавляем в него
действие «закрыть» */
s = posix_spawn_file_actions_init(&file_actions);
if (s != 0)
errExitEN(s, "posix_spawn_file_actions_init");
s = posix_spawn_file_actions_addclose(&file_actions,
STDOUT_FILENO);
if (s != 0)
errExitEN(s, "posix_spawn_file_actions_addclose");
file_actionsp = &file_actions;
break;
case \(aqs\(aq: /* -s: блокировать все сигналы в потомке */
/* создаём объект атрибутов и добавляем в него действие
«назначения сигнальной маски» */
s = posix_spawnattr_init(&attr);
if (s != 0)
errExitEN(s, "posix_spawnattr_init");
s = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK);
if (s != 0)
errExitEN(s, "posix_spawnattr_setflags");
sigfillset(&mask);
s = posix_spawnattr_setsigmask(&attr, &mask);
if (s != 0)
errExitEN(s, "posix_spawnattr_setsigmask");
attrp = &attr;
break;
}
}
/* Порождение потомка. Имя исполняемой программы и аргументы
командной строки берутся из аргументов командной строки
этой программы. Окружение исполняемой программы в потомке
делается таким же как у родителя. */
s = posix_spawnp(&child_pid, argv[optind], file_actionsp, attrp,
&argv[optind], environ);
if (s != 0)
errExitEN(s, "posix_spawn");
/* уничтожаем все объекты, которые мы создали ранее */
if (attrp != NULL) {
s = posix_spawnattr_destroy(attrp);
if (s != 0)
errExitEN(s, "posix_spawnattr_destroy");
}
if (file_actionsp != NULL) {
s = posix_spawn_file_actions_destroy(file_actionsp);
if (s != 0)
errExitEN(s, "posix_spawn_file_actions_destroy");
}
printf("PID потомка: %ld\n", (long) child_pid);
/* отслеживаем состояние потомка до его завершения */
do {
s = waitpid(child_pid, &status, WUNTRACED | WCONTINUED);
if (s == -1)
errExit("waitpid");
printf("Состояние потомка: ");
if (WIFEXITED(status)) {
printf("завершился, состояние=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("убит по сигналу %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("остановлен по сигналу %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("выполняется\n");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit(EXIT_SUCCESS); }

REFERENCED BY

⇧ Top