Spawning Processes

Spawning Processes — Порождение процессов с помощью fork()/exec().

Краткое описание

#include <glib.h> enum GSpawnError; #define G_SPAWN_ERROR enum GSpawnFlags; void (*GSpawnChildSetupFunc) (gpointer user_data); gboolean g_spawn_async_with_pipes (const gchar *working_directory, gchar **argv, gchar **envp, GSpawnFlags flags, GSpawnChildSetupFunc child_setup, gpointer user_data, GPid *child_pid, gint *standard_input, gint *standard_output, gint *standard_error, GError **error); gboolean g_spawn_async (const gchar *working_directory, gchar **argv, gchar **envp, GSpawnFlags flags, GSpawnChildSetupFunc child_setup, gpointer user_data, GPid *child_pid, GError **error); gboolean g_spawn_sync (const gchar *working_directory, gchar **argv, gchar **envp, GSpawnFlags flags, GSpawnChildSetupFunc child_setup, gpointer user_data, gchar **standard_output, gchar **standard_error, gint *exit_status, GError **error); gboolean g_spawn_command_line_async (const gchar *command_line, GError **error); gboolean g_spawn_command_line_sync (const gchar *command_line, gchar **standard_output, gchar **standard_error, gint *exit_status, GError **error); void g_spawn_close_pid (GPid pid);

Описание

Детали

enum GSpawnError

typedef enum { G_SPAWN_ERROR_FORK, /* fork failed due to lack of memory */ G_SPAWN_ERROR_READ, /* read or select on pipes failed */ G_SPAWN_ERROR_CHDIR, /* changing to working dir failed */ G_SPAWN_ERROR_ACCES, /* execv() returned EACCES */ G_SPAWN_ERROR_PERM, /* execv() returned EPERM */ G_SPAWN_ERROR_2BIG, /* execv() returned E2BIG */ G_SPAWN_ERROR_NOEXEC, /* execv() returned ENOEXEC */ G_SPAWN_ERROR_NAMETOOLONG, /* "" "" ENAMETOOLONG */ G_SPAWN_ERROR_NOENT, /* "" "" ENOENT */ G_SPAWN_ERROR_NOMEM, /* "" "" ENOMEM */ G_SPAWN_ERROR_NOTDIR, /* "" "" ENOTDIR */ G_SPAWN_ERROR_LOOP, /* "" "" ELOOP */ G_SPAWN_ERROR_TXTBUSY, /* "" "" ETXTBUSY */ G_SPAWN_ERROR_IO, /* "" "" EIO */ G_SPAWN_ERROR_NFILE, /* "" "" ENFILE */ G_SPAWN_ERROR_MFILE, /* "" "" EMFLE */ G_SPAWN_ERROR_INVAL, /* "" "" EINVAL */ G_SPAWN_ERROR_ISDIR, /* "" "" EISDIR */ G_SPAWN_ERROR_LIBBAD, /* "" "" ELIBBAD */ G_SPAWN_ERROR_FAILED /* other fatal failure, error->message * should explain */ } GSpawnError;

Коды ошибок возвращаемые при выполнении процессов.

G_SPAWN_ERROR_FORK форк не удался из-за нехватки памяти.
G_SPAWN_ERROR_READ чтение или выбор канала неудался.
G_SPAWN_ERROR_CHDIR изменение рабочего каталога неудалось.
G_SPAWN_ERROR_ACCES execv() вернул EACCES.
G_SPAWN_ERROR_PERM execv() вернул EPERM.
G_SPAWN_ERROR_2BIG execv() вернул E2BIG.
G_SPAWN_ERROR_NOEXEC execv() вернул ENOEXEC.
G_SPAWN_ERROR_NAMETOOLONG execv() вернул ENAMETOOLONG.
G_SPAWN_ERROR_NOENT execv() вернул ENOENT.
G_SPAWN_ERROR_NOMEM execv() вернул ENOMEM.
G_SPAWN_ERROR_NOTDIR execv() вернул ENOTDIR.
G_SPAWN_ERROR_LOOP execv() вернул ELOOP.
G_SPAWN_ERROR_TXTBUSY execv() вернул ETXTBUSY.
G_SPAWN_ERROR_IO execv() вернул EIO.
G_SPAWN_ERROR_NFILE execv() вернул ENFILE.
G_SPAWN_ERROR_MFILE execv() вернул EMFILE.
G_SPAWN_ERROR_INVAL execv() вернул EINVAL.
G_SPAWN_ERROR_ISDIR execv() вернул EISDIR.
G_SPAWN_ERROR_LIBBAD execv() вернул ELIBBAD.
G_SPAWN_ERROR_FAILED Некоторая другая проблема, error->message должно пояснить.

G_SPAWN_ERROR

#define G_SPAWN_ERROR g_spawn_error_quark ()

Домен ошибки для порождения процессов. Ошибки в этом домене будут из перечисления GSpawnError. Смотрите GError для информации о доменах ошибки.


enum GSpawnFlags

typedef enum { G_SPAWN_LEAVE_DESCRIPTORS_OPEN = 1 << 0, G_SPAWN_DO_NOT_REAP_CHILD = 1 << 1, /* look for argv[0] in the path i.e. use execvp() */ G_SPAWN_SEARCH_PATH = 1 << 2, /* Dump output to /dev/null */ G_SPAWN_STDOUT_TO_DEV_NULL = 1 << 3, G_SPAWN_STDERR_TO_DEV_NULL = 1 << 4, G_SPAWN_CHILD_INHERITS_STDIN = 1 << 5, G_SPAWN_FILE_AND_ARGV_ZERO = 1 << 6 } GSpawnFlags;

Флаги помещаемые в g_spawn_sync(), g_spawn_async() и g_spawn_async_with_pipes().

G_SPAWN_LEAVE_DESCRIPTORS_OPEN дескриптор открытого родительского файла будет унаследован дочерним процессом; иначе все дескрипторы кроме stdin/stdout/stderr будут закрыты перед вызовом exec() в дочернем процессе.
G_SPAWN_DO_NOT_REAP_CHILD дочерний процесс не будет автоматически получен; вы должны вызвать waitpid() или обработать SIGCHLD самостоятельно, или дочерний процесс станет зомби.
G_SPAWN_SEARCH_PATH argv[0] не должен быть абсолютным путём, он будет найден в пользовательском PATH.
G_SPAWN_STDOUT_TO_DEV_NULL стандартный вывод из дочернего процесса будет отменён, вместо направления в тоже расположение родительского стандартного вывода.
G_SPAWN_STDERR_TO_DEV_NULL стандартные ошибки дочернего процесса будут отменены.
G_SPAWN_CHILD_INHERITS_STDIN дочерний процесс унаследует стандартный ввод родителя (по умолчанию, стандартный дочерний ввод прикреплён к /dev/null).
G_SPAWN_FILE_AND_ARGV_ZERO первый элемент argv это выполняемый файл, остальные элементы являются фактически одномерным массивом параметров для помещения в файл. Обычно g_spawn_async_with_pipes() использует argv[0] как файл для выполнения и передаёт все argv в дочерний процесс.

GSpawnChildSetupFunc ()

void (*GSpawnChildSetupFunc) (gpointer user_data);

Определяет тип установочной функции помещаемой в g_spawn_async(), g_spawn_sync() и g_spawn_async_with_pipes(). На POSIX платформах она вызывается в дочернем процессе после того как GLib выполнит все запланированные установки, но перед вызовом exec(). В POSIX, действия принятые в этой функции, затронут таким образом только дочерний процесс, а не родителя.

В Windows функция вызывается в родительском процессе. Её полноценность в Windows таким образом сомнительна. В большинстве случаев выполнение функции установки в родительском процессе может иметь плохой эффект, вы должны быть очень осторожны когда портируете программы в Windows использующие дочерние функции установки.

user_data : пользовательские данные помещаемые в функцию.

g_spawn_async_with_pipes ()

gboolean g_spawn_async_with_pipes (const gchar *working_directory, gchar **argv, gchar **envp, GSpawnFlags flags, GSpawnChildSetupFunc child_setup, gpointer user_data, GPid *child_pid, gint *standard_input, gint *standard_output, gint *standard_error, GError **error);

Выполняет дочернюю программу асинхронно (ваша программа не будет блокирована для выхода из дочернего процесса). Дочерняя программа определяет только аргументы которые должны быть предоставлены массивом argv. argv должен быть NULL-завершённым массивом строк, для помещения как одномерный массив в дочерний процесс. Первая строка в argv является названием программы для выполнения. По умолчанию имя программы должно быть полным путём; переменная PATH оболочки (shell) будет использоваться для поиска только если вы поместите флаг G_SPAWN_SEARCH_PATH.

Помните что в Windows все строки или одномерные строковые массивы аргументов для этой функции и других g_spawn*() функций находятся в кодировке UTF-8, кодировка имён файлов GLib. Unicode символы которые не являются частью системной кодовой страницы которые передают в одномерном массиве аргументов будут корректно доступны в порождённой программе только если она использует широкий символьный API для поиска в её командной строке. Для C программ собранных с помощью инструментария Microsoft's достаточно создать программу имея wmain() вместо main(). wmain() имеет широкий символ одномерного массива как параметр.

По крайней мере в настоящее время mingw не поддерживает wmain(), поэтому если вы используете mingw для разработки порождаемых программ, то должны вызвать недокументированную функцию __wgetmainargs() для получения широкого символа аргументов одномерного массива и окружения. Смотрите gspawn-win32-helper.c в GLib исходниках или init.c в исходниках программы mingw для определения прототипа этой функции. Альтернативно вы можете найти широкий символ командной строки системного уровня Win32 помещаемый в порождённую программу используя функцию GetCommandLineW().

В Windows нижний уровень API создания дочерних процессов CreateProcess() не использует одномерный массив аргументов, но использует командную строку. Семейство функций библиотеки C spawn*() (которые вызывают в конечном счёте g_spawn_async_with_pipes()) помещают элементы одномерного массива аргументов вместе в командную строку, а во время выполнения C код делает соответствующую реконструкцию одномерного массива аргументов из командной строки для помещения в main(). Осложнения возникают когда вы имеете элементы одномерного массива аргументов которые содержат пробелы заключённые в двойные кавычки. Функции spawn*() не делают никакого квотирования или выхода, но с другой стороны код запуска закрывает кавычки и не выходит чтобы позволить получить аргументы с включёнными пробелами или двойными кавычками. Для работы вокруг этой ассиметрии, g_spawn_async_with_pipes() выполнит квотирование и прервёт элементы одномерного массива аргументов которые нужны ей перед вызовом функции C runtime spawn().

envp это NULL-завершённый массив строк, где каждая строка имеет форму KEY=VALUE. Это будет окружением дочернего процесса. Если envp это NULL, дочерний процесс наследует окружение его родителя.

flags должен быть поразрядным ИЛИ любых флагов которые должны влиять на поведение функции. G_SPAWN_DO_NOT_REAP_CHILD означает что дочерний процесс не будет автоматически выполнен; вы должны использовать источник GChildWatch для получения уведомления об уничтожении дочернего процесса. В конечном счёте вы должны вызвать g_spawn_close_pid() в child_pid, для освобождения ресурсов связанных с дочерним процессом. (В Unix, используется источник GChildWatch равноценный вызову waitpid() или обрабатывается сигнал SIGCHLD вручную. В Windows, вызов g_spawn_close_pid() равноценно вызову CloseHandle() для обработки возвращаемого child_pid). G_SPAWN_LEAVE_DESCRIPTORS_OPEN означает что родительский дескриптор открытого файла будет унаследован дочерним процессом; иначе все дескрипторы кроме stdin/stdout/stder будут закрыты перед вызовом exec() в дочернем процессе. G_SPAWN_SEARCH_PATH означает что argv[0] не должен быть абсолютным путём, он будет найден в пользовательской переменной PATH. G_SPAWN_STDOUT_TO_DEV_NULL означает что стандартный вывод дочернего процесса будет отменён, он будет направлен в тоже расположение что и стандартный вывод родительского процесса. Если вы используете этот флаг, standard_output должен быть NULL. G_SPAWN_STDERR_TO_DEV_NULL означает что дочерний стандартный поток error будет отменён, вместо этого он будет направлен в тоже расположение что и стандартный поток error родительского процесса. Если вы используете этот флаг, standard_error должен быть NULL. G_SPAWN_CHILD_INHERITS_STDIN означает что дочерний процесс будет наследовать родительский стандартный поток ввода (input) (по умолчанию, стандартный поток ввода дочернего процесса прикреплён к /dev/null). Если вы используете этот флаг, standard_input должен быть NULL. G_SPAWN_FILE_AND_ARGV_ZERO означает что первый элемент argv является исполняемым файлом, в то время как остальные элементы являются фактически одномерным массивом аргументов помещаемых в файл. Обычно g_spawn_async_with_pipes() использует argv[0] как исполняемый файл, и помещает остальные argv в дочерний процесс.

child_setup и user_data являются функцией и пользовательскими данными. На POSIX платформах, функция вызывается в дочернем процессе после выполнения GLib всех запланированных установок (включая создание каналов, закрытие дескрипторов файлов, etc.) но перед вызовом exec(). Таким образом, child_setup вызывается перед вызовом exec() в дочернем процессе. Очевидно что действия принятые в этой функции затронут только дочерний процесс, но не родителя. В Windows, нет разделения fork() и exec() функциональности. Дочерний процесс создаётся и выполняется единственным API вызовом, CreateProcess(). child_setup вызывается в родительском процессе как раз перед созданием дочернего процесса. Вы должны внимательно рассмотреть то что вы делаете в child_setup если вы планируете переносить свою программу в Windows.

Если не-NULL, child_pid будет заполнен в Unix с помощью ID дочернего процесса. Вы можете использовать ID процесса для отправки сигналов дочернему процессу, или для waitpid() если вы определили флаг G_SPAWN_DO_NOT_REAP_CHILD. В Windows, child_pid будет заполнен с помощью обработки дочернего процесса только если вы определили флаг G_SPAWN_DO_NOT_REAP_CHILD. Вы сможете тогда обратиться к дочернему процессу используя Win32 API, например ожидать его завершения с помощью функций WaitFor*(), или например проверить его код завершения с помощью GetExitCodeProcess(). Вы должны завершить обработку с помощью CloseHandle() или g_spawn_close_pid() когда вы больше не нуждаетесь в ней.

Если не-NULL, standard_input, standard_output, standard_error расположения будут заполнены дескрипторами файлов для записи в стандартном потоке ввода дочерних процессов или для чтения в стандартном потоке вывода или для стандартного потока error. Вызывающий g_spawn_async_with_pipes() должен закрыть этот дескриптор файла когда он больше не нужен. Если эти параметры равны NULL, соответственно канал не будет создан.

Если standard_input равен NULL, стандартный ввод дочернего процесса прикреплён к /dev/null пока не установлен G_SPAWN_CHILD_INHERITS_STDIN.

Если standard_error равен NULL, стандартный поток error дочернего процесса направлен в тоже расположение что и стандартный поток error родительского процесса пока не установлен G_SPAWN_STDERR_TO_DEV_NULL.

Если standard_output равен NULL, стандартный вывод дочернего процесса направлен в то же расположение что и стандартный вывод родительского процесса пока не установлен G_SPAWN_STDOUT_TO_DEV_NULL.

error может быть NULL для игнорирования ошибок, или не-NULL для сообщения об ошибках. Если error установлен, функция возвращает FALSE. Об ошибках сообщается даже если они происходят в дочернем процессе (например если исполняемый файл в argv[0] небыл найден). Обычно поле message возвращаемой ошибки должно отображаться пользователям. Возможные ошибки указаны в домене G_SPAWN_ERROR.

Если произошла ошибка, child_pid, standard_input, standard_output, и standard_error не будут заполнены допустимыми значениями.

Если child_pid не-NULL и не происходит ошибки то возвращаемый pid должен быть закрыт с помощью g_spawn_close_pid().

working_directory : текущий рабочий каталог дочернего процесса, или NULL для наследования родительского, в кодировке имён файлов GLib
argv : одномерный массив аргументов дочернего процесса, в кодировке имён файлов GLib
envp : окружение дочернего процесса, или NULL для наследования родительского, в кодировке имён файлов GLib
flags : флаги из GSpawnFlags
child_setup : функция запускаемая в дочернем процессе перед exec()
user_data : пользовательские данные для child_setup
child_pid : расположение для возвращаемого ID дочернего процесса, или NULL
standard_input : расположение возвращаемого дескриптора файла для записи стандартным потоком stdin дочернего процесса, или NULL
standard_output : расположение возвращаемого дескриптора файла для чтения стандартным потоком stdout дочернего процесса, или NULL
standard_error : расположение возвращаемого дескриптора файла для чтения стандартным потоком stderr дочернего процесса, или NULL
error : расположение для возвращаемой ошибки
Возвращает : TRUE при успешном выполнении, FALSE если была установлена ошибка

g_spawn_async ()

gboolean g_spawn_async (const gchar *working_directory, gchar **argv, gchar **envp, GSpawnFlags flags, GSpawnChildSetupFunc child_setup, gpointer user_data, GPid *child_pid, GError **error);

Смотрите g_spawn_async_with_pipes() для полного описания; эта функция просто вызывает g_spawn_async_with_pipes() без всяких каналов.

working_directory : текущий рабочий каталог дочернего процесса, или NULL для наследования родительского
argv : одномерный массив аргументов дочернего процесса
envp : окружение дочернего процесса, или NULL для наследования родительского
flags : флаги из GSpawnFlags
child_setup : функция для запуска в дочернем процессе перед exec()
user_data : пользовательские данные для child_setup
child_pid : расположение для возвращаемого ID дочернего процесса, или NULL
error : расположение для возвращаемой ошибки
Возвращает : TRUE при успешном выполнении, FALSE если установлена ошибка

g_spawn_sync ()

gboolean g_spawn_sync (const gchar *working_directory, gchar **argv, gchar **envp, GSpawnFlags flags, GSpawnChildSetupFunc child_setup, gpointer user_data, gchar **standard_output, gchar **standard_error, gint *exit_status, GError **error);

Выполняет дочерний процесс синхронно (ждёт выхода из дочернего процесса перед возвращением). Весь вывод из дочернего процесса сохраняется в standard_output и standard_error, если эти параметры не-NULL. Если exit_status не-NULL, статус выхода из дочернего процесса сохраняется как если бы было возвращено waitpid(); стандартные UNIX макросы такие как WIFEXITED() и WEXITSTATUS() должны использоваться для оценки состояния выхода. Если произошла ошибка, нет данных возвращённых в standard_output, standard_error, или exit_status.

Эта функция вызывает g_spawn_async_with_pipes() внутренне; смотрите полные детали в других параметрах и детали как эти функции работают в Windows.

working_directory : текущий рабочий каталог дочернего процесса, или NULL для наследования родительского
argv : одномерный массив аргументов дочернего процесса
envp : окружение дочернего процесса, или NULL для наследования родительского
flags : флаги из GSpawnFlags
child_setup : функция для запуска в дочернем процессе перед exec()
user_data : пользовательские данные для child_setup
standard_output : расположение возвращаемого дочернего потока output
standard_error : расположение возвращаемых дочерних сообщений об ошибках
exit_status : расположение для возвращаемого статуса выхода дочернего процесса, который возвращается из waitpid()
error : расположение для возвращаемой ошибки
Возвращает : TRUE при успешном выполнении, FALSE если была установлена ошибка.

g_spawn_command_line_async ()

gboolean g_spawn_command_line_async (const gchar *command_line, GError **error);

Простая версия g_spawn_async() которая анализирует командную строку с помощью g_shell_parse_argv() и направляет в g_spawn_async(). Выполняет командную строку в фоновом режиме. В отличие от g_spawn_async(), флаг G_SPAWN_SEARCH_PATH включен, другие флаги нет. Помните что G_SPAWN_SEARCH_PATH может иметь безопасные включения, поэтому рассмотрите непосредственное использование g_spawn_async() если возможно. Возможные ошибки указаны в g_shell_parse_argv() и g_spawn_async().

Встречаются те же проблемы в Windows применении, что и для g_spawn_command_line_sync().

command_line : командная строка
error : расположение для возвращаемых ошибок
Возвращает : TRUE при успешном выполнении, FALSE если установлена ошибка.

g_spawn_command_line_sync ()

gboolean g_spawn_command_line_sync (const gchar *command_line, gchar **standard_output, gchar **standard_error, gint *exit_status, GError **error);

Простая версия g_spawn_sync() с удалёнными мало-используемыми параметрами, принимает командную строку вместо одномерного массива аргументов. Смотрите g_spawn_sync() для изучения всех деталей. command_line будет анализироваться с помощью g_shell_parse_argv(). В отличие от g_spawn_sync(), флаг G_SPAWN_SEARCH_PATH включен. Помните что G_SPAWN_SEARCH_PATH может иметь безопасные включения, поэтому рассмотрите непосредственное использование g_spawn_sync() если возможно. Возможные ошибки происходят из g_spawn_sync() и from g_shell_parse_argv().

Если exit_status не-NULL, статус выхода дочернего процесса сохраняется как возвращаемый waitpid(); стандартные UNIX макросы WIFEXITED() и WEXITSTATUS() должны использоваться для оценки статуса выхода.

В Windows, пожалуйста помните включение g_shell_parse_argv() анализирующую command_line. Анализ выполняется согласно правилам оболочки Unix, а не правил командного интерпретатора Windows. Пробел является разделителем, и backslashes является специальным. Поэтому вы не можете прост поместить command_line содержащую канонический Windows путь, как "c:\\program files\\app\\app.exe", поскольку backslashes будут подавлены, и пробелы будут действовать как разделители. Вам нужно заключать такие пути в одиночные кавычки, например "'c:\\program files\\app\\app.exe' 'e:\\folder\\argument.txt'".

command_line : командная строка
standard_output : расположение возвращаемого дочернего потока output
standard_error : расположение возвращаемых дочерних ошибок
exit_status : расположение для возвращаемого статуса выхода дочернего процесса, который возвращает waitpid()
error : расположение для возвращаемых ошибок
Возвращает : TRUE при успешном выполнении, FALSE если установлена ошибка

g_spawn_close_pid ()

void g_spawn_close_pid (GPid pid);

На некоторых платформах, особенно WIN32, тип GPid представляет ресурс который должен быть закрыт для предотвращения утечки ресурсов. g_spawn_close_pid() предназначена для этих целей. Она должна использоваться на всех платформах, даже при том что она ничего не делает в UNIX.

pid : идентификатор процесса для закрытия