vfork

title: vfork(2)

text:
# vfork(2)

## ИМЯ
vfork - создаёт дочерний процесс и блокирует родительский

## ОБЗОР
\#include <sys/types.h>

\#include <unistd.h>

pid_t vfork(void);

Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

vfork():

Начиная с glibc 2.12:

```
(_XOPEN_SOURCE >= 500) && ! (_POSIX_C_SOURCE >= 200809L)

    || /* начиная с glibc 2.19: */ _DEFAULT_SOURCE

    || /* в версиях glibc <= 2.19: */ _BSD_SOURCE
```

до glibc 2.12: _BSD_SOURCE || _XOPEN_SOURCE >= 500

## ОПИСАНИЕ

### Описание в стандарте
(Из POSIX) Функция vfork() аналогична fork(2) за тем исключением, что поведение не определено, если процесс, созданный vfork(), изменяет любые данные, кроме переменной типа pid_t, используемой в качестве значения, возвращаемого vfork(), или возвращается из функции, из которой была вызвана функция vfork(), или вызывает любую функцию до удачного исполнения _exit(2) или одной из функций семейства exec(3).

### Описание в Linux
vfork(), так же как и fork(2), создаёт дочерний процесс для вызывающего процесса. Подробности, возвращаемые значения и ошибки смотрите в fork(2).

vfork() — это специальный вариант clone(2). Он используется для создания новых процессов без копирования таблиц страниц родительского процесса. Это может использоваться в приложениях, критичных к производительности, для создания дочерних процессов, сразу же запускающих execve(2).

Вызов vfork() отличается от fork(2) тем, что вызывающая нить блокируется до тех пор, пока не завершится потомок (обычно, вызовом _exit(2) или, что ненормально, из-за принятого необработанного сигнала) или не выполнит execve(2). До этих пор потомок имеет общую память с родителем, включая стек. Потомок не должен выходить из текущей функции или вызывать exit(3) (что приводит к вызовы обработчиков выхода, настроенных родительским процессом и сбрасывает буферы stdio(3) родителя), но может вызвать _exit(2).

Как и у fork(2), дочерний процесс, созданный vfork(), наследует копии различных атрибутов вызвавшего процесса (например, дескрипторы файлов, обработчики сигналов и текущий рабочий каталог); вызов vfork() отличается только в применении виртуального адресного пространства (как описывалось выше).

Сигналы передаются родителю после того, как потомок разблокирует его память (т.е. после того, как потомок завершится или вызовет execve(2)).

### Историческое описание
В Linux вызов fork(2) реализован при помощи страниц, «копируемых при записи» (copy-on-write), поэтому единственная задержка, возникающая при вызове fork(2) — это время, необходимое для создания копии таблиц страниц родительского процесса и уникальной структуры описания задачи дочернего процесса. Однако, в прошлом для fork(2) могло требоваться создание полной копии пространства данных вызывающего процесса, что часто было ненужно, так как в потомке сразу следовал запуск функции exec(3). Поэтому для большей эффективности в BSD был предложен системный вызов vfork(), который не копировал адресное пространство процесса, а использовал то же самое пространство и управления нитью, блокируя родительский процесс до вызова execve(2) или до прекращения работы потомка. Родительский процесс останавливался до тех пор, пока потомок использовал его ресурсы. Использование vfork() было ненадёжно: например, сохранность данных родительского процесса зависела от того, хранились ли на тот момент переменные в регистрах.

## СООТВЕТСТВИЕ СТАНДАРТАМ
4.3BSD; POSIX.1-2001 (помечен как УСТАРЕВШИЙ). Из POSIX.1-2008 описание vfork() было удалено.

Требования, предъявляемые стандартами к vfork(), не такие жёсткие как те, которые предъявляются к fork(2), поэтому в реализации достаточно просто сделать их синонимами. В частности, программист не может полагаться на блокировку родителя до завершения потомка или до вызова им execve(2), и не может полагаться на специфическое поведение возникновения общей памяти.

## ЗАМЕЧАНИЯ
Некоторые считают, что в семантике vfork() есть архитектурный недостаток, а в справочной странице BSD написано следующее: «Данный системный вызов будет удалён после того, как будут правильно реализованы соответствующие механизмы разделения ресурсов системы. Пользователи не должны опираться на существующую семантику общей памяти vfork(), то есть программа должна быть аналогична программе с fork(2)». Однако, даже при том, что современные аппаратные средства управления памятью уменьшили разницу в производительности между fork(2) и vfork(), есть другие причины почему в Linux и других операционных системах vfork() ещё существует:

- Для некоторых критичных к производительности приложений очень важна та маленькая прибавка к производительности, предоставляемая vfork().

- Вызов vfork() может быть реализован в системах, у которых нет блока управления памятью (MMU), а fork(2) невозможно реализовать на таких системах (из POSIX.1-2008 вызов vfork() удалён; для реализации эквивалента fork(2)+exec(3) в системах без MMU в POSIX предлагается использовать функцию posix_spawn(3)).

- В системах с малым количеством памяти vfork() при запуске новой программы не выполняет временное выделение памяти (смотрите описание /proc/sys/vm/overcommit_memory в proc(5)) (это особенно полезно, если огромный родительский процесс хочет выполнить маленькую вспомогательную программу в дочернем процессе). Вызов fork(2) в этом случае или потребуется выделения количества памяти как у родительского процесса (если включён жёсткий учёт обязательств) или перерасходует память с риском завершения процесса посредством сторожа расходования памяти ядра (OOM).

### Предостережения
Потомок не должен изменять память не ожидаемым образом, так как такие изменения будут видны родительскому процессу после завершения потомка или выполнении другой программы. При таком отношении особенно остро стоит проблема в обработчиках сигналов: если обработчик сигналов, вызванный в потомке (созданном vfork()), изменяет память, то эти изменения могут привести к нарушению целостности состояния процесса с точки зрения родителя (например, изменения памяти были бы видны родителю, а изменения состояния открытых файловых дескрипторов не видны).

Если vfork() вызывается многонитиевом процессе, то в ожидании завершения процесса или запуска новой программы приостанавливается только вызывающая нить. Это означает, что потомок совместно использует адресное пространство другим выполняющимся кодом. Это может быть опасно, если другая нить в родительском процессе изменяет полномочия (с помощью setuid(2) и подобных), так как теперь есть два процесса с разным уровнем прав, выполняемых в одном адресном пространстве. Как пример представим, что многонитиевая программа, работающая с правами суперпользователя, создаёт потомка с помощью vfork(). После vfork() нить в родительском процессе понижает права процесса до непривилегированных, чтобы выполнить некий недоверенный код (например, модуль, открытый через dlopen(3)). В этом случае появляется уязвимость, если родительский процесс использует mmap(2) для отображения кода, то он будет выполнен в привилегированном дочернем процессе.

### Замечания, касающиеся Linux
Обработчики fork, установленные с помощью pthread_atfork(3), не вызываются когда многонитиевая программа использует вызовы библиотеки нитей NPTL vfork(). Обработчики fork вызываются в этом случае в программе, в которой используется библиотека нитей LinuxThreads. (См. в pthreads(7) описание библиотек нитей Linux.)

Вызов vfork() эквивалентен вызову clone(2) со следующим значением flags:

CLONE_VM | CLONE_VFORK | SIGCHLD

### История
Системный вызов vfork() впервые появился в 30BSD. В 4.4BSD он стал синонимом fork(2), но в NetBSD он был введён снова; смотрите http://www.netbsd.org/Documentation/kernel/vfork.html. В Linux этот системный вызов был эквивалентом fork(2), примерно, до ядра 2.2.0-pre6. Начиная с 2.2.0-pre9 (на i386 и немного позже на других архитектурах), он стал независимым системным вызовом. Его поддержка была добавлена в glibc 2.0.112.

## ДЕФЕКТЫ
Обработка сигналов ещё более запутана и различается от системы к системе. В справочной странице BSD написано следующее: «Для исключения возможности взаимных блокировок процессы, находящиеся в середине исполнения vfork(), никогда не получат сигналов SIGTTOU или SIGTTIN, хотя вывод или ioctl всегда разрешены, а попытки ввода приводят к ситуации появления конца файла».

## СМОТРИТЕ ТАКЖЕ
clone(2), execve(2), _exit(2), fork(2), unshare(2), wait(2)


vhangup

package: man-pages-ru

title: vhangup(2)

text:
# vhangup(2)

## ИМЯ
vhangup - имитирует прекращение работы текущего терминала

## ОБЗОР
\#include <unistd.h>

int vhangup(void);

Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

vhangup():

```
    начиная с glibc 2.21:

        _DEFAULT_SOURCE

    в glibc 2.19 и 2.20:

        _DEFAULT_SOURCE || (_XOPEN_SOURCE && _XOPEN_SOURCE < 500)

    до glibc 2.19 включительно:

        _BSD_SOURCE || (_XOPEN_SOURCE && _XOPEN_SOURCE < 500)
```

## ОПИСАНИЕ
vhangup() имитирует прекращение работы на текущем терминале. Этот вызов выполняет действия, необходимые для очистки терминала перед приглашением ко входу.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
EPERM

Вызывающий процесс не имеет достаточно прав для вызова vhangup(); требуется мандат CAP_SYS_TTY_CONFIG.

## СООТВЕТСТВИЕ СТАНДАРТАМ
Данный вызов существует только в Linux и не должен использоваться в программах, которые должны быть переносимыми.

## СМОТРИТЕ ТАКЖЕ
init(1), capabilities(7)

branch: sisyphus


title: vm86(2)

summary: войти в виртуальный режим 8086

text:
# vm86(2)

## ИМЯ
vm86old, vm86 - войти в виртуальный режим 8086

## ОБЗОР
\#include <sys/vm86.h>

int vm86old(struct vm86_struct *info);

int vm86(unsigned long fn, struct vm86plus_struct *v86);

## ОПИСАНИЕ
Системный вызов vm86() был введён в Linux 0.97p2. В Linux 2.1.15 и 2.0.28 он был переименован в vm86old() и был введён новый vm86(). Описание структуры struct vm86_struct было изменено в 1.1.8 и 1.1.9.

Данные вызовы заставляют вызывающий процесс войти в режим VM86 (виртуальный режим 8086 в литературе по Intel) и используются dosemu.

Режим VM86 — это эмуляция реального режима внутри задачи, которая работает в защищённом режиме.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
EFAULT

Возвращённое значение является есть только для i386 и указывает на проблему получения данных из пространства пользователя.

ENOSYS

Возвращённое значение указывает, что вызов не реализован на данной архитектуре.

EPERM

Существует сохранённый стек ядра (это проверка ядра; сохранённый стек должен существовать только внутри самого режима vm86).

## СООТВЕТСТВИЕ СТАНДАРТАМ
Данный вызов является специфичным для Linux на 32-битных процессорах Intel и не должен использоваться в программах, которые задумываются как переносимые на другие платформы.


vmsplice

title: vmsplice(2)

text:
# vmsplice(2)

## ИМЯ
vmsplice - соединяет пользовательские страницы памяти с каналом

## ОБЗОР

```
#define _GNU_SOURCE         /* см. feature_test_macros(7) */
#include <fcntl.h>
#include <sys/uio.h>
```

```
ssize_t vmsplice(int fd, const struct iovec *iov,
                 unsigned long nr_segs, unsigned int flags);
```

## ОПИСАНИЕ
Если fd открыт для записи, то системный вызов vmsplice() отображает nr_segs областей пользовательской памяти, описанных iov, в канал. Если fd открыт для чтения, то системный вызов vmsplice() заполняет nr_segs областей пользовательской памяти, описанных iov, из канала. Файловый дескриптор fd должен указывать на канал.

Указатель iov указывает на массив структур iovec, определённых в <sys/uio.h>:

```
struct iovec {

    void  *iov_base;        /* начальный адрес */

    size_t iov_len;         /* количество байт */
};
```

Аргумент flags представляет собой битовую маску, которая составляется логическим сложением (OR) следующих значений:

SPLICE_F_MOVE

Не используется в vmsplice(); см. splice(2).

SPLICE_F_NONBLOCK

Не блокировать ввод-вывод; подробности в splice(2).

SPLICE_F_MORE

В данный момент никак не влияет при указании в vmsplice(), но это может измениться; см. splice(2).

SPLICE_F_GIFT

Предоставить ядру пользовательские страницы. Приложение, возможно, не изменяло эту память, иначе страничный кэш и данные на диске будут различны. Передача страниц ядру означает, что последующий вызов splice(2) с флагом SPLICE_F_MOVE сможет переместить страницы; если этот флаг не указан, то последующий splice(2) с флагом SPLICE_F_MOVE должен скопировать страницы. Также, данные должны быть выровнены по странице: по адресам памяти и размеру.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении vmsplice() возвращается количество байт, переданных в канал. При ошибке vmsplice() возвращает -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
EAGAIN

В указан flags SPLICE_F_NONBLOCK, и операция вызвала бы блокировку.

EBADF

Неправильное значение fd или оно не указывает на канал.

EINVAL

Значение nr_segs больше IOV_MAX; или, если задан SPLICE_F_GIFT, не выровнена память.

ENOMEM

Не хватает памяти.

## ВЕРСИИ
Системный вызов vmsplice() впервые появился в Linux 2.6.17; поддержка в glibc добавлена в версии 2.5.

## СООТВЕТСТВИЕ СТАНДАРТАМ
Данный вызов есть только в Linux.

## ЗАМЕЧАНИЯ
Вызов vmsplice() следует другим функциям векторизованного чтения/записи при возникновении ограничений на количество передаваемых сегментов. Это ограничение равно IOV_MAX, определяемое в <limits.h>. Сейчас это значение равно 1024.

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

## СМОТРИТЕ ТАКЖЕ
splice(2), tee(2), pipe(7)


wait

title: wait(2)

summary: ожидает смену состояния процесса

text:
# wait(2)

## ИМЯ
wait, waitpid, waitid - ожидает смену состояния процесса

## ОБЗОР
\#include <sys/types.h>

\#include <sys/wait.h>

pid_t wait(int *wstatus);

pid_t waitpid(pid_t pid, int *wstatus, int options);

int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

/* Это интерфейс glibc и POSIX; информацию по

системному вызову ядра смотрите в ЗАМЕЧАНИЯ. */

Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

waitid():

начиная с glibc 2.26: _XOPEN_SOURCE >= 500 ||

_POSIX_C_SOURCE >= 200809L

в glibc 2.25 и старее:

_XOPEN_SOURCE

|| /* начиная с glibc 2.12: */ _POSIX_C_SOURCE >= 200809L

|| /* в версиях glibc <= 2.19: */ _BSD_SOURCE

## ОПИСАНИЕ
Данные системные вызовы используются для ожидания изменения состояния процесса-потомка вызвавшего процесса и получения информации о потомке, чьё состояние изменилось. Сменой состояния считается: прекращение работы потомка, останов потомка по сигналу, продолжение работы потомка по сигналу. Ожидание прекращения работы потомка позволяет системе освободить ресурсы, использовавшиеся потомком; если ожидание не выполняется, то прекративший работу потомок остаётся в системе в состоянии "зомби (zombie)" (см. ЗАМЕЧАНИЯ далее).

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

### wait() и waitpid()
Системный вызов wait() приостанавливает выполнение вызвавшей нити до тех пор, пока не прекратит выполнение один из её потомков. Вызов wait(&wstatus) эквивалентен:

```
waitpid(-1, &wstatus, 0);
```

Системный вызов waitpid() приостанавливает выполнение вызвавшей нити до тех пор, пока не изменится состояние потомка, заданного аргументом pid. По умолчанию waitpid() ожидает только прекращения работы потомка, но это можно изменить через аргумент options как описано далее.

Значением pid может быть:

< -1

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

-1

означает, что нужно ждать любого потомка.

0

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

> 0

означает, что нужно ждать любого потомка, чей идентификатор процесса равен pid.

Значение options создаётся путем битовой операции ИЛИ над следующими константами:

WNOHANG

означает немедленный возврат, если ни один потомок не завершил выполнение.

WUNTRACED

также возвращаться, если есть остановленный потомок (но не трассируемый через ptrace(2)). Состояние трассируемого остановленного потомка предоставляется даже если этот аргумент не указан.

WCONTINUED (начиная с Linux 2.6.10)

также возвращаться, если работа остановленного потомка возобновилась из-за получения сигнала SIGCONT.

(Аргументы, имеющиеся только в Linux, см. далее.)

Если wstatus не равен NULL, то wait() и waitpid() сохраняют информацию о состоянии в переменной типа int, на которую указывает wstatus. Это целое число можно исследовать с помощью следующих макросов (они принимают в качестве аргумента само целое, а не указатель на него как wait() и waitpid()!):

WIFEXITED(wstatus)

возвращает истинное значение, если потомок нормально завершился, то есть вызвал exit(3) или _exit(2), или вернулся из функции main().

WEXITSTATUS(wstatus)

возвращает код завершения потомка. Он состоит из восьми младших бит аргумента status, который потомок указал при вызове exit(3) или _exit(2) или в аргументе оператора return в функции main(). Этот макрос можно использовать, только если WIFEXITED вернул истинное значение.

WIFSIGNALED(wstatus)

возвращает истинное значение, если потомок завершился из-за сигнала.

WTERMSIG(wstatus)

возвращает номер сигнала, который привел к завершению потомка. Этот макрос можно использовать, только если WIFSIGNALED вернул истинное значение.

WCOREDUMP(wstatus)

возвращает истину, если потомок создал дамп памяти (смотрите core(5)). Этот макрос можно использовать только, если при WIFSIGNALED возвращается истинное значение.

Данный макрос не описан в POSIX.1-2001 и недоступен в некоторых реализациях UNIX (например, AIX, SunOS). Поэтому указывайте его внутри #ifdef WCOREDUMP ... #endif.

WIFSTOPPED(wstatus)

возвращает истинное значение, если потомок остановлен по сигналу; это возможно только, если при вызове был указан флаг WUNTRACED или если над потомком выполняется трассировка (см. ptrace(2)).

WSTOPSIG(wstatus)

возвращает номер сигнала, из-за которого потомок был остановлен. Этот макрос можно использовать только, если при WIFSTOPPED возвращается истинное значение.

WIFCONTINUED(wstatus)

(начиная с Linux 2.6.10) возвращает истинное значение, если потомок продолжил работу, получив сигнал SIGCONT.

### waitid()
Системный вызов waitid() (доступен, начиная с Linux 2.6.9) предоставляет более полный контроль над тем, какого изменения состояния нужно ждать у потомка.

Аргументы idtype и id определяют какого(их) потомков ждать:

idtype == P_PID

Ждать потомка, чей ID процесса совпадает с id.

idtype == P_PGID

Ждать любого потомка, чей ID группы процессов совпадает с id.

idtype == P_ALL

Ждать любого потомка; значение id игнорируется.

Ожидаемые изменения состояния потомков задаются следующими флагами в options (объединяются через OR):

WEXITED

Ждать завершения потомков.

WSTOPPED

Ждать потомков, которые завершатся по получению сигнала.

WCONTINUED

Ждать возобновления работы потомков (ранее остановленных) при получении сигнала SIGCONT.

Дополнительно с помощью OR в options могут задаваться следующие флаги:

WNOHANG

Как в waitpid().

WNOWAIT

Оставить потомка в состоянии ожидания; последующий вызов wait сможет снова получить информацию о состоянии потомка.

При успешном возврате, waitid() заполняет следующие поля в структуре siginfo_t, указываемой из infop:

si_pid

ID процесса потомка.

si_uid

Реальный пользовательский ID потомка. (Это поле не заполняется в большинстве других реализаций.)

si_signo

Всегда устанавливается в SIGCHLD.

si_status

Заполняется кодом завершения потомка, заданном в _exit(2) (или в exit(3)), или номером сигнала, который прервал, остановил или продолжил работу потомка. Что записано в данном поле можно определить по значению поля si_code.

si_code

Устанавливается в одно из: CLD_EXITED (потомок вызвал _exit(2)); CLD_KILLED (потомок завершил работу по сигналу); CLD_DUMPED (потомок завершил работу по сигналу и был создан дамп памяти); CLD_STOPPED (потомок приостановлен по сигналу); CLD_TRAPPED (трассируемый потомок был захвачен); или CLD_CONTINUED (потомок продолжил работу по сигналу SIGCONT).

Если в options указан флаг WNOHANG и нет потомков в состоянии ожидания, то waitid() сразу возвращает 0, а состояние структуры siginfo_t, на которую указывает infop, зависит от реализации. Чтобы (точно) отличать этот случай от того, что потомок был в ожидаемом состоянии, обнулите поле si_pid перед вызовом и проверьте ненулевое значение в этом поле после отработки вызова.

В POSIX.1-2008 Technical Corrigendum 1 (2013) добавлено требование, что при указании WNOHANG в options и нет потомков в состоянии ожидания, то вызов waitid() должен возвращать в структуре обнулённые поля si_pid и si_signo. В Linux и других реализациях придерживаются этого требования, поэтому не нужно обнулять поле si_pid перед вызовом waitid(). Однако в этом не все реализации следуют POSIX.1.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
В случае успешного выполнения wait() возвращает ID процесса завершившегося потомка; при ошибке возвращается -1.

В случае успешного выполнения waitpid() возвращает ID процесса потомка, чьё состояние изменилось; если задан флаг WNOHANG и существует один или более потомков, заданных в pid, без изменённого состояния, то возвращается 0. При ошибке возвращается -1.

Вызов waitid() возвращает 0 в случае успешного выполнения или если задан флаг WNOHANG и пока не существует потомка(ов), указанного в pid,с изменённым состоянием. При ошибке возвращается -1.

Каждый из этих вызовов записывает в errno соответствующую причину ошибки.

## ОШИБКИ
ECHILD

(для wait()) У вызвавшего процесса нет ожидающих потомков.

ECHILD

(для waitpid() или waitid()) Процесс, заданный pid (waitpid()) или idtype и id (waitid()), не существует или не является потомком вызвавшего процесса. (Это может случиться для своего потомка, если действие для SIGCHLD установлено в SIG_IGN. См. также раздел Linux Notes о нитях.)

EINTR

Флаг WNOHANG не задан и был пойман неблокируемый сигнал или SIGCHLD; см. signal(7).

EINVAL

Недопустимое значение options.

## СООТВЕТСТВИЕ СТАНДАРТАМ
SVr4, 4.3BSD, POSIX.1-2001.

## ЗАМЕЧАНИЯ
Потомок, который завершился, но которого не ждали, становится «зомби» (zombie). Ядро поддерживает минимальный набор информации о процессах зомби (PID, состояние завершения, использованные ресурсы), чтобы позже позволить родителю выполнить процесс ожидания для получения информации о потомке. До тех пор, пока зомби не будет удалён из системы через процесс ожидания (wait), он занимает пространство (slot) в таблице процессов ядра, и если таблица заполнится, станет невозможно создавать новые процессы. Если родительский процесс завершает работу, то его потомки «зомби» (если есть) усыновляются процессом init(1) (или ближайшим «сборщиком», определённым посредством вызова prctl(2)с операцией PR_SET_CHILD_SUBREAPER); init(1) автоматически выполняет процедуру ожидания для удаления зомби.

В POSIX.1-2001 указано, что если для SIGCHLD указан флаг SIG_IGN или SA_NOCLDWAIT (смотрите sigaction(2)), то завершающиеся потомки не становятся зомби, а вызов wait() или waitpid() заблокирует выполнение до тех пор, пока все потомки не завершат работу, и затем завершится с ошибкой errno, равной ECHILD (в оригинальном стандарте POSIX такое значение настройки SIGCHLD в SIG_IGN не определено. Заметим, что хотя поведение SIGCHLD по умолчанию является «игнорирование», явная установка в SIG_IGN приводит другому обращению с потомками зомби).

Linux 2.6 соответствует данной спецификации. Однако, Linux 2.4 (и ранее) не соответствует: если вызов wait() или waitpid() сделан при игнорировании SIGCHLD, вызов работает как если бы SIGCHLD не игнорировался, то есть, вызов блокирует работу до тех пор, пока следующий потомок не завершит работу и затем возвращает ID процесса и состояние этого потомка.

### Замечания, касающиеся Linux
В ядре Linux нити, управляемые ядром, устройством не отличаются от процесса. Нить — это просто процесс, который создан уникальным (существующим только в Linux) системным вызовом clone(2); другие процедуры, такие как переносимая версия pthread_create(3), также реализованы с помощью clone(2). До Linux 2.4, нить представляла собой специализированный вариант процесса, и, как следствие, нить не могла ждать потомков другой нити, даже когда последняя принадлежала той же группе нитей. Однако, в POSIX вписали такую функциональность, и, начиная с Linux 2.4, нить может, и по умолчанию будет ждать потомков других нитей в той же группе нитей.

Следующие значения options, присущие только Linux, используются для потомков, созданных с помощью clone(2); начиная с Linux 4.7, они также могут использоваться с waitid():

__WCLONE

Ждать только «клонированных (clone)» потомков. Если не указано, то ожидаются только «не клонированные» потомки («клонированным» считается потомок, который не доставляет сигнал, или сигнал, отличный от SIGCHLD, своему родителю при завершении). Этот аргумент игнорируется, если также указано __WALL.

__WALL (начиная с Linux 2.4)

Ждать всех потомков независимо от типа ("клонированный" или "неклонированный").

__WNOTHREAD (начиная с Linux 2.4)

Не ждать потомков других нитей в той же группе нитей. Это поведение по умолчанию до Linux 2.4.

Начиная с Linux 4.7, в случае, когда потомок был вызван с помощью ptrace, флаг __WALL назначается автоматически.

### Отличия между библиотекой C и ядром
В действительности, wait() — библиотечная функция, которая (в glibc) реализована через вызов wait4(2).

Для некоторых архитектур нет системного вызова waitpid(); его заменяет интерфейс, реализованный через обёрточную функцию библиотеки C, которая вызывает wait4(2).

Системный вызов ядра waitid() имеет пятый аргумент с типом struct rusage *. Если его значение не равно NULL, то он используется для возврата информации по используемым ресурсам в потомке, в том же виде что и wait4(2). Подробности смотрите в getrusage(2).

## ДЕФЕКТЫ
Согласно POSIX.1-2008, приложение, вызывающее waitid(), должно убедиться, что infop указывает на структуру siginfo_t (т. е., что это указатель не равен null). В Linux, если infop равно NULL, то waitid() выполняется успешно и возвращает ID процесса ожидавшегося потомка. Приложения не должны полагаться на это несогласованное, нестандартное и ненужное свойство.

## ПРИМЕР
В следующей программе показано использование fork(2) и waitpid(). Программа создаёт процесс потомок. Если программа запущена без параметров, то потомок приостанавливает выполнение с помощью pause(2), чтобы позволить пользователю послать сигнал потомку. Иначе, если в командной строке задан параметр, то потомок завершает работу сразу, используя переданное в параметре командной строки целое число как код завершения. Процесс родитель работает в цикле, следя за потомком с помощью waitpid(), и использует макросы W*(), описанные ранее, для анализа значения состояния ожидания.

Следующий сеанс работы в оболочке показывает работу с программой:

```
$ ./a.out &
Child PID is 32360
[1] 32359
$ kill -STOP 32360
stopped by signal 19
$ kill -CONT 32360
continued
$ kill -TERM 32360
killed by signal 15
[1]+  Done                    ./a.out
$
```

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

```
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{

    pid_t cpid, w;

    int wstatus;

    cpid = fork();

    if (cpid == -1) {

        perror("fork");

        exit(EXIT_FAILURE);

    }

    if (cpid == 0) {            /* Код, выполняемый потомком */

        printf("Child PID is %ld\n", (long) getpid());

        if (argc == 1)

            pause();                    /* Ожидание сигналов */

        _exit(atoi(argv[1]));

    } else {                    /* Код, выполняемый родителем */

        do {

            w = waitpid(cpid, &wstatus, WUNTRACED | WCONTINUED);

            if (w == -1) {

                perror("waitpid");

                exit(EXIT_FAILURE);

            }

            if (WIFEXITED(wstatus)) {

                printf("exited, status=%d\n", WEXITSTATUS(wstatus));

            } else if (WIFSIGNALED(wstatus)) {

                printf("killed by signal %d\n", WTERMSIG(wstatus));

            } else if (WIFSTOPPED(wstatus)) {

                printf("stopped by signal %d\n", WSTOPSIG(wstatus));

            } else if (WIFCONTINUED(wstatus)) {

                printf("continued\n");

            }

        } while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus));

        exit(EXIT_SUCCESS);

    }
}
```

## СМОТРИТЕ ТАКЖЕ
_exit(2), clone(2), fork(2), kill(2), ptrace(2), sigaction(2), signal(2), wait4(2), pthread_create(3), core(5), credentials(7), signal(7)


title: wait4(2)

summary: ожидает смену состояния в стиле BSD

text:
# wait4(2)

## ИМЯ
wait3, wait4 - ожидает смену состояния в стиле BSD

## ОБЗОР

```
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
```

```
pid_t wait3(int *wstatus, int options,
            struct rusage *rusage);
```

```
pid_t wait4(pid_t pid, int *wstatus, int options,
            struct rusage *rusage);
```

Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

wait3():

начиная с glibc 2.19:

_DEFAULT_SOURCE || _XOPEN_SOURCE >= 500

glibc 2.19 и старее:

_BSD_SOURCE || _XOPEN_SOURCE >= 500

wait4():

начиная с glibc 2.19:

_DEFAULT_SOURCE

glibc 2.19 и старее:

_BSD_SOURCE

## ОПИСАНИЕ
Эти функции являются нестандартными; в новых программах используйте waitpid(2) или waitid(2).

Системные вызовы wait3() и wait4() похожи на waitpid(2), но дополнительно возвращают информацию об использовании ресурсов потомком в структуре, указываемой rusage.

Помимо использования аргумента rusage, вызов wait3():

```
wait3(wstatus, options, rusage);
```

эквивалентен:

```
waitpid(-1, wstatus, options);
```

Подобно этому, вызов wait4():

```
wait4(pid, wstatus, options, rusage);
```

эквивалентен:

```
waitpid(pid, wstatus, options);
```

Другими словами, wait3() ожидает любого потомка, а для wait4() может быть указан определённый потомок или потомки, которых нужно ожидать. Подробней см. wait(2).

Если rusage не равно NULL, то struct rusage, на которую он указывает, будет заполнен информацией о работе потомка. Подробней см. getrusage(2).

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
Как в waitpid(2).

## ОШИБКИ
Как в waitpid(2).

## СООТВЕТСТВИЕ СТАНДАРТАМ
4.3BSD.

В SUSv1 определена wait3(); в SUSv2 включена wait3(), но помечена как УСТАРЕВШАЯ; удалена в SUSv3.

## ЗАМЕЧАНИЯ
Включать <sys/time.h> в настоящее время не требуется, но это увеличивает переносимость. (Безусловно, в <sys/resource.h> определена структура rusage с полями типа struct timeval, которая определена в <sys/time.h>.)

### Отличия между библиотекой C и ядром
В Linux, wait3() является библиотечной функцией, реализованной на основе системного вызова wait4().

## СМОТРИТЕ ТАКЖЕ
fork(2), getrusage(2), sigaction(2), signal(2), wait(2), signal(7)


write

title: write(2)

summary: запись в файловый дескриптор

text:
# write(2)

## ИМЯ
write - запись в файловый дескриптор

## ОБЗОР
\#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);

## ОПИСАНИЕ
Вызов write() пишет до count байт из буфера, начиная с buf, в файл, на который ссылается файловый дескриптор fd.

Количество записанных байт может быть меньше чем count если, например, недостаточно места на физическом носителе, или исчерпан отведённый лимит ресурса RLIMIT_FSIZE (см. setrlimit(2)), или вызов был прерван обработчиком сигналов после уже записанных меньше чем count байт. (См. также pipe(7).)

В случае с файлами, разрешающими позиционирование (т.е., к которым можно применить lseek(2), например, обычные файлы), запись производится по текущему файловому смещению, а смещение файла увеличивается на реальное число записанных байт. Если файл был открыт с помощью open(2) с аргументом O_APPEND, то перед записью файловое смещение устанавливается в конец файла. Согласование файлового смещения и операции записи выполняются атомарно.

В POSIX требуется, чтобы read(2), который может быть вызван сразу после write(), возвращал новые данные. Заметим, что не все файловые системы соответствуют стандарту POSIX.

В соответствие с POSIX.1, если count больше SSIZE_MAX, то результат зависит от реализации; смотрите ЗАМЕЧАНИЯ по верхнему пределу в Linux.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении возвращается количество записанных байт. При ошибке возвращается -1 и errno устанавливается в соответствующее значение.

Заметим, что при успешном выполнении write() может передать меньше чем count байт. Такая частичная запись может возникать по нескольким причинам; например, из-за недостаточного количества места на диске, на который пишутся все запрошенные байты или из-за прерывания блокировки write() сокета, канала или подобного обработчиком сигнала после частичной передачи, но до того, как были переданы все запрашиваемый байты. При даже частичной записи вызывающий может запустить другой вызов write() для передачи оставшихся байт. Последующий вызов или передаст остальные байты, или может завершиться ошибкой (например, если переполнен диск).

Если count равен нулю и fd указывает на обычный файл, то write() может вернуть ошибку, если обнаружена одна из перечисленных ниже ошибок. Если ошибок не обнаружено или проверка ошибки не производилась, то возвращается 0 без каких-либо других последствий. Если count равен нулю и fd указывает на отличный от обычного файл, то результат не определён.

## ОШИБКИ
EAGAIN

Файловый дескриптор fd указывает на файл, не являющийся сокетом и помеченный как неблокирующий ввод/вывод (O_NONBLOCK), а запись вызовет блокировку. См. open(2) для дальнейшей информации по флагу O_NONBLOCK.

EAGAIN или EWOULDBLOCK

Файловый дескриптор fd указывает на сокет, который помечен как неблокирующий ввод/вывод (O_NONBLOCK), а запись вызовет блокировку. По POSIX.1-2001 разрешено возвращать ошибку в обоих случая и не требуется, чтобы эти константы имели одно значение, поэтому переносимые приложения должны проверять обе причины.

EBADF

Значение fd не является правильным файловым дескриптором или он не открыт для записи.

EDESTADDRREQ

Значение fd ссылается на сокет дейтаграмм, у которого с помощью connect(2) не назначен адрес другой стороны.

EDQUOT

Исчерпана пользовательская квота на дисковые блоки файловой системы с файлом, на который указывает fd.

EFAULT

buf находится за пределами доступного вам адресного пространства.

EFBIG

Попытка записать в файл, который превышает заданное при реализации ограничение на размер файла или ограничение на размер файла для текущего процесса, или запись в позицию после максимально разрешённого смещения.

EINTR

Этот вызов был прерван сигналом, перед тем как были записаны какие-либо данные; см signal(7).

EINVAL

fd присоединён к объекту, который не подходит для записи; или файл был открыт с указанием флага O_DIRECT, или неправильно выравнено адрес в buf, значение count или файловое смещение.

EIO

Во время изменения иноды возникла низкоуровневая ошибка ввода/вывода. Эта ошибка может относится к отложенным (write-back) данным предыдущего вызова write(), который выполнялся с другим файловым дескриптором для этого же файла. Начиная с Linux 4.13 ошибки отложенных данных поступают с обещанием, что о них может быть сообщено следующему вызову. Результаты запросов write() будут переданы последующему fsync(2) (независимо от того, сообщалось ли об этом write()). Также EIO может возникать у сетевых файловых систем, когда консультативная блокировка была убрана у дескриптора файла и потеряна. Подробности смотрите в абзаце Потерянные блокировки в fcntl(2).

ENOSPC

На устройстве, содержащем файл, на который ссылается fd, нет свободного места.

EPERM

Выполнение операции предотвращено опечатыванием (file seal); смотрите fcntl(2).

EPIPE

fd ссылается на конвейер или сокет, у которого закрыто чтение. Когда такое случается, пишущий процесс также получит сигнал SIGPIPE. (Таким образом, возвращаемое значение можно будет увидеть только если программа перехватывает, блокирует или игнорирует этот сигнал.)

В зависимости от объекта, на который указывает fd, могут происходить и другие ошибки.

## СООТВЕТСТВИЕ СТАНДАРТАМ
SVr4, 4.3BSD, POSIX.1-2001.

Согласно SVr4, запись может быть прервана в любом месте (с возвратом EINTR), а не только перед тем как будут записаны какие-либо данные.

## ЗАМЕЧАНИЯ
Типы данных size_t и ssize_t представляют собой, соответственно, беззнаковый и знаковый целочисленный тип, определены в POSIX.1.

Успешный возврат из вызова write() не даёт никаких гарантий, что данные сохранены на диске. В некоторых файловых системах, включая NFS, даже не гарантируется, что для данных было зарезервировано место. В этом случае некоторые ошибки могут появиться только в будущем write(), fsync(2) или даже close(2). Единственный способ получить гарантированную запись — вызвать fsync(2) после записи всех данных.

Если write() прерван обработчиком сигналов до начала записи, то вызов возвращает ошибку EINTR; если он прерван после начала записи, то вызов считается успешным, и возвращается число записанных байт.

В Linux write() (и похожие системные вызовы) передаст не больше 0x7ffff000 (2 147 479 552) байт, возвращая число байт, переданных на самом деле (это утверждение справедливо как к 32-битным, так и к 64-битным системам).

Возвращаемое значение ошибки при выполнении write() прямого ввода-вывода не означает ошибки записи целиком. Данные могут быть записаны частично, а по смещению в файле, на котором write() остановился, данные должны считаться некорректными.

## ДЕФЕКТЫ
В соответствие с POSIX.1-2008/SUSv4 раздел XSI 2.9.7 ("Thread Interactions with Regular File Operations"):

Следующие функции должны выполняться атомарно по отношению друг к другу, чтобы работать с обычными файлами или символическими ссылками так, как указано в POSIX.1-2008: …

Среди перечисленных в программном интерфейсе есть write() и writev(2). И среди действий, которые должны выполняться атомарно между нитями (и процессами), если обновление файлового смещения. Однако в Linux до версии 3.14 это было не так: если два процесса с общим открытым файловым описанием (смотрите open(2)) выполняют write() (или writev(2)) одновременно, то операции ввода-вывода не атомарны при обновлении файлового смещения; в результате записанные двумя процессами блоки данных могут (некорректно) перекрываться. Эта ошибка исправлена в Linux 3.14.

## СМОТРИТЕ ТАКЖЕ
close(2), fcntl(2), fsync(2), ioctl(2), lseek(2), open(2), pwrite(2), read(2), select(2), writev(2), fwrite(3)