futex

title: futex(2)

text:
# futex(2)

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

## ОБЗОР

```
#include <linux/futex.h>
#include <sys/time.h>
```

```
int futex(int *uaddr, int futex_op, int val,
          const struct timespec *timeout,   /* or: uint32_t val2 */
          int *uaddr2, int val3);
```

Замечание: В glibc нет обёрточной функции для данного системного вызова; смотрите ЗАМЕЧАНИЯ.

## ОПИСАНИЕ
Системный вызов futex() предоставляет программам метод для ожидания пока определённое условие не станет истинным. Обычно, этот системный вызов используется блокирующая конструкция в контексте синхронизации общей памяти. При использовании фьютексов основные операции синхронизации выполняются в пространстве пользователя. Программы пользовательского пространства выполняются системный вызов futex() только когда нужно, чтобы программа вошла в режим ожидания на долгий срок, пока условие не станет истинным. Также futex() можно использовать для пробуждения процессов или нитей, ожидающих определённого условия.

Фьютекс это 32-битное значение — называемое далее словом фьютекса — чей адрес передаётся в системный вызов futex() (фьютексы имеют размер в 32 бита на всех платформах, включая 64-битные системы). Все операции с фьютексами выполняются с этим значением. Чтобы сделать фьюетекс общим между процессами, фьютекс помещается в область общем памяти, создаваемой с помощью (например) mmap(2) или shmat(2) (то есть слово фьютекса может иметь различающиеся виртуальные адреса в разных процессах, но эти адреса всё равно указывают на одну область в физической памяти). В многонитевых программах достаточно поместить слово фьютекса в глобальную переменную, доступную из всех нитей.

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

Одним из применений фьютексов является реализация блокировок. Состояние блокировки (т. е., получена или не получена) может быть представлено в виде атомарно доступного флага в общей памяти. При отсутствии конкурентов, нить может получить доступ или изменить состояние блокировки атомарными инструкциями, например атомарно изменяя её значение с не полученной на полученную с помощью атомарной инструкции сравнения-и-обмена (эти инструкции целиком выполняются в пользовательском режим, и ядро с состоянием блокировки ничего не делает). С другой стороны, нить может не получить блокировку, так как она уже получена другой нитью. После этого она может передать флаг блокировки в виде слова фьютекса, значением которого будет ожидаемое значение состояния получения в операции ожидания futex(). Операция futex() блокируется, только когда блокировка всё ещё имеется (т. е., значение слова фьютекса совпадает с «состояния получения»). При освобождении блокировки нить сначала сбрасывает состояние блокировки в не полученное, а затем вызывает операцию фьютекса, которая пробуждает нить, заблокированную флагом блокировки, используя его как слово фьютекса (в дальнейшем это может быть оптимизировано для устранения ненужных пробуждений). О том, как использовать фьютексы, смотрите futex(7).

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

Заметим, что для использования фьютексов не требуется явных действий по инициализации и удалению; ядро поддерживает фьютексы (т. е., внутренняя часть реализации ядра) только в операции FUTEX_WAIT, описанной далее, обрабатывая определённое слово фьютекса.

### Аргументы
В аргументе uaddr указывает слово фьютекса. На всех платформах фьютексы это целые числа размером в четыре байта, которые должны быть выровнены по четырёх байтовой границе. Операция, выполняемая с фьютексом, задаётся в аргументе futex_op; какое значение будет задаваться в val, зависит от futex_op.

Остальные аргументы (timeout, uaddr2 и val3) требуются только для определённых операций с фьютексами и описаны далее. Там, где эти аргументы не нужны, они игнорируются.

Для некоторых операций блокировки аргументом timeout является указатель на структуру timespec, в которой задаётся время ожидания операции. Однако, несмотря на прототип, показанный выше, для некоторых операций используются только младшие четыре байта этого аргумента вместо целого числа, назначение которого определяется операцией. Для этих операций ядро преобразует значение timeout сначала к unsigned long, затем к uint32_t. Отсюда и до конца страницы этот аргумент будет называться val2, когда он интерпретируется в такой манере.

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

Интерпретация последнего целочисленного аргумента, val3, зависит от операции.

### Операции с фьютексами
Аргумент futex_op состоит из двух частей: команды, задающей выполняемую операцию, и объединённые биты нуля или более параметров, которые изменяют поведение операции. Параметры, которые можно включать в futex_op:

FUTEX_PRIVATE_FLAG (начиная с Linux 2.6.22)

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

Для удобства, в <linux/futex.h> определён набор констант с суффиксом _PRIVATE, которые эквивалентны всем операциям, перечисленным ниже, но с добавленным константным значением флага FUTEX_PRIVATE_FLAG. То есть, существуют FUTEX_WAIT_PRIVATE, FUTEX_WAKE_PRIVATE и т. д.

FUTEX_CLOCK_REALTIME (начиная с Linux 2.6.28)

Этот бит параметра может применяться только с операциями FUTEX_WAIT_BITSET, FUTEX_WAIT_REQUEUE_PI и FUTEX_WAIT (начиная с Linux 4.5).

Если он указан, то ядро измеряет timeout по часам CLOCK_REALTIME.

Если он не указан, то ядро измеряет timeout по часам CLOCK_MONOTONIC.

Операцией в futex_op может быть одно из:

FUTEX_WAIT (начиная с Linux 2.6.0)

Эта операция проверяет, что значение слова фьютекса, на которое указывает адрес uaddr по прежнему содержит ожидаемое значение val и если это так, то засыпает, ожидая операции FUTEX_WAKE для этого слова фьютекса. Загрузка значения слова фьютекса является атомарным доступом к памяти (т. е., используются атомарные машинные инструкции соответствующей архитектуры). Эта загрузка, сравнение с ожидаемым значением и запуск сна выполняются атомарно и целиком упорядочены относительно других фьютекс-операций с этим словом фьютекса. Если нить начала засыпать, то считается что она — ожидающий этого слова фьютекса. Если значение фьютекса не совпадает с val, то вызов немедленно завершается с ошибкой EAGAIN.

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

Если значение timeout не равно NULL, то структура, на которую он указывает, определяет время ожидания (этот интервал будет округлён до точности системных часов, и гарантируется, что он не наступит раньше положенного). По умолчанию время ожидания измеряется по часам CLOCK_MONOTONIC, но начиная с Linux 4.5 можно выбрать часы CLOCK_REALTIME, указав FUTEX_CLOCK_REALTIME в futex_op. Если timeout равно NULL, то вызов блокируется бессрочно.

Замечание: при FUTEX_WAIT значение timeout интерпретируется как относительное. В этом отличие от других операций над фьютексами, в которых timeout интерпретируется как абсолютное значение. Чтобы получить эквивалент FUTEX_WAIT с абсолютным временем ожидания укажите FUTEX_WAIT_BITSET в val3 вместе с FUTEX_BITSET_MATCH_ANY.

Аргументы uaddr2 и val3 игнорируются.

FUTEX_WAKE (начиная с Linux 2.6.0)

Эта операция пробуждает не больше val процессов, ожидающих (например, внутри FUTEX_WAIT) слово фьютекса по адресу uaddr. Чаще всего, val присваивают или 1 (пробудить одного ожидающего), или INT_MAX (пробудить всех ожидающих). Не гарантируется, что разбудят каких-то определённых ожидающих (например, что ожидающий с большим приоритетом планировщика будет разбужен раньше ожидающего, имеющего меньший приоритет).

Аргументы timeout, uaddr2 и val3 игнорируются.

FUTEX_FD (начиная с Linux 2.6.0 и по Linux 2.6.25 включительно)

Эта операция создаёт файловый дескриптор, который связан с фьютексом по адресу uaddr. Вызывающий должен закрыть возвращённый файловый дескриптор после использования. Если другой процесс или нить выполняет операцию FUTEX_WAKE со словом фьютекса, то файловый дескриптор будет отмечен как доступный для чтения в select(2), poll(2) и epoll(7).

Файловый дескриптор можно использовать для получения асинхронных уведомлений: если val не равно нулю, то когда другой процесс или нить выполняют FUTEX_WAKE, то вызывающий примет сигнал с номером, который был указан в val.

Аргументы timeout, uaddr2 и val3 игнорируются.

Так как по своей природе операция FUTEX_FD приводит к состязательности, она была удалена из Linux, начиная с версии 2.6.26.

FUTEX_REQUEUE (начиная с Linux 2.6.0)

Эта операция выполняет ту же задачу, что и FUTEX_CMP_REQUEUE (смотрите далее), за исключением того, что она не проверяет используемое значение в val3 (аргумент val3 игнорируется).

FUTEX_CMP_REQUEUE (начиная с Linux 2.6.7)

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

Загрузка из uaddr является атомарным доступом к памяти (т. е., используются атомарные машинные инструкции соответствующей архитектуры). Эта загрузка, сравнение с val3 и перестановка в очередь ожидающих выполняются атомарно и целиком упорядочены относительно других фьютекс-операций с этим словом фьютекса.

Типичными значениями val являются 0 или 1 (указание INT_MAX бесполезно, так как это сделало бы операцию FUTEX_CMP_REQUEUE эквивалентной FUTEX_WAKE). Значение ограничения, указанное в val2, обычно, или 1 или INT_MAX (указание 0 бесполезно, так как это сделало бы операцию FUTEX_CMP_REQUEUE эквивалентной FUTEX_WAIT).

Операция FUTEX_CMP_REQUEUE была добавлена в качестве замены имевшейся FUTEX_REQUEUE. Различие в том, что проверку значения по адресу uaddr можно использовать для гарантии того, что перестановка в очередь произойдёт только при определённых условиях, что в определённых случаях позволит избежать состязательности.

И FUTEX_REQUEUE и FUTEX_CMP_REQUEUE можно использовать для недопущения «нашествия орды» из пробудившихся, которое может произойти при использовании FUTEX_WAKE в случаях, когда всем разбуженным ожидающим требуется заблокировать другой фьютекс. Рассмотрим следующий сценарий, где несколько ожидающих нитей ждут B, очередь ожидания реализована с помощью фьютекса:

```
lock(A)
while (!check_value(V)) {

    unlock(A);

    block_on(B);

    lock(A);
};
unlock(A);

```

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

FUTEX_WAKE_OP (начиная с Linux 2.6.14)

Эта операция была добавлена для работы в некоторых случаях из пользовательского пространства, в которых нужно одновременно учитывать несколько фьютексов. Самый известный пример — реализация pthread_cond_signal(3), которая требует операций для работы с двумя фьютексами: один для реализации мьютекса, а другой для реализации очереди ожидания, связанной с переменной условия. Операция FUTEX_WAKE_OP позволяет это реализовать без увеличения состязательности и контекстного переключения.

Операция FUTEX_WAKE_OP эквивалентна выполнению следующего кода, при чём, атомарно и полностью упорядочено в соответствии с другими фьютекс-операциями, выполняемыми над двумя указанными словами фьютекса:

```
int oldval = *(int *) uaddr2;
*(int *) uaddr2 = oldval op oparg;
futex(uaddr, FUTEX_WAKE, val, 0, 0, 0);
if (oldval cmp cmparg)

    futex(uaddr2, FUTEX_WAKE, val2, 0, 0, 0);

```

Иначе говоря, FUTEX_WAKE_OP делает следующее:

- сохраняет первоначальное значение слова фьютекса по адресу uaddr2 и выполняет операцию изменения значения фьютекса по адресу uaddr2; это атомарная операция с памятью по чтению-изменению-записи (т. е., используются атомарные машинные инструкции на соответствующей архитектуре);

- пробуждает не более val ожидающих у фьютекса слова фьютекса по адресу uaddr; и

- в зависимости от результата проверки первоначального значения слова фьютекса по адресу uaddr2, пробуждает не более val2 ожидающих у фьютекса слова фьютекса по адресу uaddr2.

Операция и сравнение, которое будет выполнено, кодируется в битах аргумента val3. Графически, кодирование выглядит так:

```
+---+---+-----------+-----------+
|оп |сра|   аргоп   |  аргсра   |
+---+---+-----------+-----------+

  4   4       12          12    <== кол-во бит

```

В виде кода это выглядит так:

```
#define FUTEX_OP(op, oparg, cmp, cmparg) \

                (((op & 0xf) << 28) | \

                ((cmp & 0xf) << 24) | \

                ((oparg & 0xfff) << 12) | \

                (cmparg & 0xfff))

```

Указанные выше op и cmp могут содержат один из кодов, перечисленных далее. Компоненты oparg и cmparg являются числовыми литералами, с учётом замечаний далее.

Компонент op может иметь одно из следующих значений:

```
FUTEX_OP_SET        0  /* uaddr2 = oparg; */
FUTEX_OP_ADD        1  /* uaddr2 += oparg; */
FUTEX_OP_OR         2  /* uaddr2 |= oparg; */
FUTEX_OP_ANDN       3  /* uaddr2 &= ~oparg; */
FUTEX_OP_XOR        4  /* uaddr2 ^= oparg; */

```

Также, битовое сложение следующего значения с op приводит к использованию (1 << oparg) в качестве операнда:

```
FUTEX_OP_ARG_SHIFT  8  /* исп. (1 << oparg) как операнд */

```

В поле cmp может быть одно из:

```
FUTEX_OP_CMP_EQ  0  /* если (oldval == cmparg) — пробудить */
FUTEX_OP_CMP_NE  1  /* если (oldval != cmparg) — пробудить */
FUTEX_OP_CMP_LT  2  /* если (oldval < cmparg) — пробудить */
FUTEX_OP_CMP_LE  3  /* если (oldval <= cmparg) — пробудить */
FUTEX_OP_CMP_GT  4  /* если (oldval > cmparg) — пробудить */
FUTEX_OP_CMP_GE  5  /* если (oldval >= cmparg) — пробудить */

```

Возвращаемое значение операции FUTEX_WAKE_OP — сумма количества разбуженных ожидающих фьютекса uaddr и количества разбуженных ожидающих фьютекса uaddr2.

FUTEX_WAIT_BITSET (начиная с Linux 2.6.25)

Эта операция подобна FUTEX_WAIT, за исключением того, что val3 используется для передачи 32-битной маски в ядро. Данная битовая маска, в которой должен быть установлен хотя бы один бит, хранится в ядре во внутреннем состоянии ожидающего. Подробности смотрите в описании FUTEX_WAKE_BITSET.

Если значение timeout не равно NULL, то структура, на которую он указывает, определяет абсолютное время ожидания. Если timeout равно NULL, то операция блокируется бессрочно.

Аргумент uaddr2 игнорируется.

FUTEX_WAKE_BITSET (начиная с Linux 2.6.25)

Данная операция подобна FUTEX_WAKE, за исключением того, что val3 используется для передачи 32-битной маски в ядро. Данная битовая маска, в которой должен быть установлен хотя бы один бит, используется для выбора ожидающих, которые должны быть разбужены. Выбор выполняется путём побитового И битовой маски «wake» (т. е., значения val3) и битовой маски, которая хранится в ядре во внутреннем состоянии ожидающего (битовая маска «wait», устанавливающаяся с помощью FUTEX_WAIT_BITSET). Все ожидающие, для которых результат побитового И не равен нулю, пробуждаются; оставшиеся ожидающие продолжают спать.

Влияние FUTEX_WAIT_BITSET и FUTEX_WAKE_BITSET позволяет выбирать пробуждающихся из многих ожидающих, которые заблокированы на один фьютекс. Однако заметим, что в зависимости от варианта применения, использование данного свойства комбинирования битовой маски с фьютексом может быть менее эффективно, чем простое использование нескольких фьютексов, так как использование комбинирования битовой маски требует от ядра проверки всех ожидающих фьютекса, включая тех, которые и не нужно было бы будить (т. е., у них неподходящий набор бит в их битовой маске «wait»).

Константу FUTEX_BITSET_MATCH_ANY, которая соответствует всем установленным битам в 32-битной маске, можно использовать в аргументе val3 для FUTEX_WAIT_BITSET и FUTEX_WAKE_BITSET. Кроме различий в обработке аргумента timeout, операция FUTEX_WAIT эквивалентна FUTEX_WAIT_BITSET с val3, равным FUTEX_BITSET_MATCH_ANY, то есть разрешается будить любого пробуждающего. Операция FUTEX_WAKE эквивалентна FUTEX_WAKE_BITSET с val3, равным FUTEX_BITSET_MATCH_ANY, то есть пробуждается любой(ые) пробуждающий.

Аргументы uaddr2 и timeout игнорируются.

### Наследование приоритета из-за фьютексов
В Linux поддерживается наследование приоритета из-за фьютексов priority-inheritance (PI), так как требуется решать проблему обратного приоритета, которая встречается у обычных блокировок фьютексов. Проблема обратного приоритета возникает, когда задача с высоким приоритетом блокируется в ожидании получения блокировки, которую удерживает задача с низким приоритетом, в то время как задачи со средним приоритетом постоянно вытесняют задачу с низким приоритетом с ЦП. В следствии этого, выполнение задачи с низким приоритетом никак не продвигается к освобождению блокировки, и задача с высоким приоритетом остаётся заблокированной.

Наследование приоритета — это механизм, который решает проблему обратного приоритета. С его помощью, когда задача с высоким приоритетом блокируется из-за удержания блокировки задачей с низким приоритетом, приоритет задачи с низким приоритетом временно повышается до приоритета, имеющегося у заблокированной задачи, и поэтому не происходит вытеснения задачами с средним приоритетом, что способствует ускорению освобождения блокировки. Чтобы это работало, наследование приоритета должно быть транзитивным, то есть если задача с высоким приоритетом заблокирована, из-за удержания блокировки задачей с низким приоритетом, которая сама заблокирована из-за удержания блокировки другой задачей со средним приоритетом (и так далее, по цепочке произвольной длины), то для обеих этих задач (или, шире, всех задач в заблокированной цепочке) повышается приоритет, который равен приоритету задачи с высоким приоритетом.

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

Операции с PI-фьютексами, описанные далее, отличаются от других операций с фьютексами в том, что они следуют политике использования значения слова фьютекса:

- Если блокировка не получена, то значение слова фьютекса должно быть равно 0.

- Если блокировка получена, то значение слова фьютекса должно быть равно ID нити (TID; смотрите gettid(2)), которой оно принадлежит.

- Если блокировка получена и есть претендующие на неё нити, то в значении слова фьютекса должен быть установлен бит FUTEX_WAITERS; иначе говоря, это значение равно:

FUTEX_WAITERS | TID

(заметим, что некорректное слово PI-фьютекса не имеет владельца и FUTEX_WAITERS)

С этой действующей политикой приложение пространства пользователя может получить свободную блокировку или освободить блокировку с помощью атомарных инструкций, выполняемых в пользовательском режиме (например, операцией сравнение-и-обмен cmpxchg на архитектуре x86). Получение блокировки состоит просто из использования сравнения-и-обмена для атомарного изменения значения слова фьютекса на TID вызывающего, если предыдущее значение было равно 0. Для освобождения блокировки требуется использовать сравнение-и-обмен для изменения значения слова фьютекса на 0, если предыдущее значение равно ожидаемому TID.

Если фьютекс уже получен (т. е. имеет ненулевое значение), то ожидающие должны применить операцию FUTEX_LOCK_PI для получения блокировки. Если другие нити ждут блокировку, то в значении фьютекса установлен бит FUTEX_WAITERS; в этом случае владелец блокировки должен применить операцию FUTEX_UNLOCK_PI для освобождения блокировки.

В случаях, когда вызывающие переходят в ядро (т. е., требуется выполнение вызова futex()), после этого они напрямую работают с так называемым RT-мьютексом, механизмом блокировок ядра, которым реализована требуемая семантика наследования приоритета. После получения RT-мьютекса, значение фьютекса обновляется соответствующим образом, перед возврата вызывающей нити в пространство пользователя.

Важно упомянуть, что ядро обновит значение слова фьютекса до возврата в пространство пользователя (это предотвращает возможность попадания значения слова фьютекса в некорректное состояние, такое, что имея владельца, значение равно 0, или имея ожидающих, не установлен бит FUTEX_WAITERS).

Если фьютекс связан с RT-мьютексом в ядре (т. е., есть заблокированные ожидающие) и владелец фьютекса/RT-мьютекса неожиданно завершился, то ядро очищает RT-мьютекс и передаёт его следующему ожидающему. Это, в свою очередь, требует, чтобы значение в пользовательском пространстве было изменено соответствующим образом. Для сообщения о необходимости этого ядро изменяет бит FUTEX_OWNER_DIED в слове фьютекса вместе со сменой ID нити нового владельца. Пользовательское пространство может определить такую ситуацию по установленному биту FUTEX_OWNER_DIED и затем, соответствующим образом, очистить устаревшее состояние, возникшее из-за закончившего работу владельца.

PI-фьютексы обрабатываются при указании в futex_op одного из значений, перечисленных далее. Заметим, что операции с PI-фьютексами должны использовать попарно и учитывать некоторые дополнительные требования:

- Парой к операциям FUTEX_LOCK_PI и FUTEX_TRYLOCK_PI является FUTEX_UNLOCK_PI. Операция FUTEX_UNLOCK_PI должна применяться только к фьютексам, принадлежащим вызывающей нити, определённой значением политики, или же возникнет ошибка EPERM.

- Парой к операции FUTEX_WAIT_REQUEUE_PI является FUTEX_CMP_REQUEUE_PI. Она должна применяться для перехода с не PI-фьютекса к PI-фьютексу (или возникает ошибка EINVAL). Также, val (количество разбуживаемых ожидающих) должно равняться 1 (или возникает ошибка EINVAL).

Операции с PI-фьютексами:

FUTEX_LOCK_PI (начиная с Linux 2.6.18)

Данная операция используется после попытки получить блокировку через атомарную инструкцию в пространстве пользователя, которая завершилась с ошибкой из-за того, что слово фьютекса не равно нулю — содержит value—specifically, because it contained the TID (PID в этом пространстве имён) владельца блокировки.

Операция проверяет значение слова фьютекса по адресу uaddr. Если значение равно 0, то ядро пытается атомарно изменить слово фьютекса на TID вызывающего. Если слово фьютекса не равно нулю, то ядро атомарно устанавливает бит FUTEX_WAITERS, который указывает владельцу фьютекса, что он не может разблокировать фьютекс в пространстве пользователя атомарным способом посредством установки значения фьюетекса в 0. После этого ядро:

1.

Пытается найти нить-владельца по TID.

2.

Создаёт или повторно использует состояние ядра от имени владельца (если это первый ожидающий, то для этого фьютекса не состояния ядра, поэтому состояние ядра создаётся блокировкой RT-мьютекса и владелец фьютекса становится владельцем RT-мьютекса. Если ожидающие уже есть, то используется имеющееся состояние).

3.

Присоединяет ожидающего к фьютексу (т. е., ожидающий ставится в очередь списка ожидающих на основе RT-мьютекса).

Если есть более одного ожидающего, то перестановка ожидающего в очередь выполняется в порядке убывания приоритета (упорядочивание по приоритету описано в разделе об алгоритмах планирования SCHED_DEADLINE, SCHED_FIFO и SCHED_RR в sched(7)). Владелец наследует от ожидающего пропускную способность ЦП (если ожидающий работает по алгоритму планирования SCHED_DEADLINE) или приоритет (если ожидающий работает по алгоритму планирования SCHED_RR или SCHED_FIFO). При обнаружении вложенности блокировки и клинча такое наследование распространяется по всей цепочке блокировки.

В аргументе timeout задаётся время ожидания захвата блокировки. Если timeout равно NULL, то структура, на которую он указывает, определяет абсолютное время ожидания, отсчитываемое по часам CLOCK_REALTIME. Если timeout равно NULL, то операция может быть в блокировке неопределённо долго.

Аргументы uaddr2, val и val3 игнорируются.

FUTEX_TRYLOCK_PI (начиная с Linux 2.6.18)

Эта операция пытается получить блокировку по адресу uaddr. Она вызывается, когда не удалось выполнить атомарное получение из пользовательского пространства, так как слово фьютекса не равно 0.

Так как ядро имеет больший доступ к информации о состоянии, чем пользовательское пространство, получение блокировки из ядра может осуществиться, в случаях когда слово фьютекса (т. е., информация о состоянии доступна из пользовательского пространства) устарело (FUTEX_WAITERS и/или FUTEX_OWNER_DIED). Это может случиться, если владелец фьютекса неожиданно завершился. Пользовательское пространство не может учесть это событие не получив состязательности, но ядро может решить данную проблему и получить блокировку.

Аргументы uaddr2, val, timeout и val3 игнорируются.

FUTEX_UNLOCK_PI (начиная с Linux 2.6.18)

Данная операция будит ожидающего с самым высоким приоритетом, который ждёт фьютекс по адресу из uaddr посредством операции FUTEX_LOCK_PI.

Операция вызывается, когда значение по адресу uaddr пользовательского пространства невозможно изменить атомарно с TID (владельца) на 0.

Аргументы uaddr2, val, timeout и val3 игнорируются.

FUTEX_CMP_REQUEUE_PI (начиная с Linux 2.6.31)

Данная операция является PI-аналогом операции FUTEX_CMP_REQUEUE. Она перестанавливает ожидающих, заблокированных с помощью FUTEX_WAIT_REQUEUE_PI для uaddr, из очереди не PI-фьютекса источника (uaddr) в очередь PI-фьютекса назначения (uaddr2).

Как и FUTEX_CMP_REQUEUE, эта операция пробуждает не более val ожидающих, которые ждут фьютекса по адресу uaddr. Однако у FUTEX_CMP_REQUEUE_PI значение val должно быть равно 1 (чтобы избежать «нашествия орды»). Оставшиеся ожидающие удаляются из очереди ожидания фьютекса-источника по адресу uaddr и добавляются в очередь ожидания фьютекса-назначения по адресу uaddr2.

Аргументы val2 и val3 служат тем же целям, что и в FUTEX_CMP_REQUEUE.

FUTEX_WAIT_REQUEUE_PI (начиная с Linux 2.6.31)

Ждать не PI-фьютекса по адресу uaddr и, потенциально быть перемещённым в очередь (при операции FUTEX_CMP_REQUEUE_PI из другой задачи) PI-фьютекса по адресу uaddr2. Операция ожидания на адресе uaddr такая же как для FUTEX_WAIT.

Ожидающий может быть удалён из ожидающих на адресе uaddr перемещения в очередь у uaddr2 при операции FUTEX_WAKE из другой задачи. В этом случае операция FUTEX_WAIT_REQUEUE_PI завершается с ошибкой EAGAIN.

Если значение timeout не равно NULL, то структура, на которую он указывает, определяет абсолютное время ожидания. Если timeout равно NULL, то операция блокируется бессрочно.

Аргумент val3 игнорируется.

Операции FUTEX_WAIT_REQUEUE_PI и FUTEX_CMP_REQUEUE_PI добавлены для довольно узкого варианта применения — поддержки переменных условия нитей POSIX с наследованием приоритета. Идея в том, что эти операции всегда должны использоваться попарно, для поддержания синхронизации между пользовательским пространством и ядром. То есть в операции FUTEX_WAIT_REQUEUE_PI приложение пользовательского пространства заранее задаёт назначение для перемещения в очередь, которое проводится операцией FUTEX_CMP_REQUEUE_PI.

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

При успешном выполнении возвращаемое значение зависит от операции:

FUTEX_WAIT

Значение 0 возвращается, если вызывающий был разбужен. Заметим, что пробуждение также может быть вызвано часто используемыми вариантами использования фьютексов в не связанном коде, которое случается, если память под слово фьютекса использовалась ранее (например, при типичной реализации фьютексов на основе мьютексов Pthreads это может возникать при определённых условиях). Поэтому вызывающий всегда должен консервативно предполагать, что возвращаемое значение 0 может означать побочное пробуждение (spurious wake-up), и учитывать значение слово фьютекса (т. е. схема с синхронизацией пользовательского пространства) при принятии решения нужна дальнейшее ожидание или нет.

FUTEX_WAKE

Возвращается количество разбуженных ожидающих.

FUTEX_FD

Возвращается новый файловый дескриптор, связанный с фьютексом.

FUTEX_REQUEUE

Возвращается количество разбуженных ожидающих.

FUTEX_CMP_REQUEUE

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

FUTEX_WAKE_OP

Возвращается общее количество разбуженных ожидающих. Это сумма разбуженных ожидающих у двух фьютексов для слов фьютексов по адресам uaddr и uaddr2.

FUTEX_WAIT_BITSET

Возвращается 0, если вызывающий был разбужен. Смотрите в описании FUTEX_WAIT, как это правильно учитывать на практике.

FUTEX_WAKE_BITSET

Возвращается количество разбуженных ожидающих.

FUTEX_LOCK_PI

Возвращается 0, если фьютекс был успешно заблокирован.

FUTEX_TRYLOCK_PI

Возвращается 0, если фьютекс был успешно заблокирован.

FUTEX_UNLOCK_PI

Возвращается 0, если фьютекс был успешно разблокирован.

FUTEX_CMP_REQUEUE_PI

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

FUTEX_WAIT_REQUEUE_PI

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

## ОШИБКИ
EACCES

Нет доступа на чтение памяти слова фьютекса.

EAGAIN

(FUTEX_WAIT, FUTEX_WAIT_BITSET, FUTEX_WAIT_REQUEUE_PI) Значение, на которое указывает uaddr, не было равно ожидаемому значению val на момент вызова.

Замечание: в Linux символические имена EAGAIN и EWOULDBLOCK (оба есть в разных частях кода фьютекса ядра) имеют одинаковое значение.

EAGAIN

(FUTEX_CMP_REQUEUE, FUTEX_CMP_REQUEUE_PI) Значение, на которое указывает uaddr, не равно ожидаемому значению val3.

EAGAIN

(FUTEX_LOCK_PI, FUTEX_TRYLOCK_PI, FUTEX_CMP_REQUEUE_PI) ID нити владельца фьютекса по адресу uaddr (для FUTEX_CMP_REQUEUE_PI — uaddr2) вскоре закончит работу, но не выполнил очистку внутреннего состояния. Попробуйте ещё раз.

EDEADLK

(FUTEX_LOCK_PI, FUTEX_TRYLOCK_PI, FUTEX_CMP_REQUEUE_PI) Слово фьютекса по адресу uaddr уже заблокировано вызывающим.

EDEADLK

(FUTEX_CMP_REQUEUE_PI) Во время перемещения в другую очередь ожидающего PI-фьютекса со словом фьютекса по адресу uaddr2 ядро обнаружило тупиковую блокировку (deadlock).

EFAULT

Требуемый аргумент указателя (т. е., uaddr, uaddr2 или timeout) не указывает на допустимый адрес пользовательского пространства.

EINTR

Операция FUTEX_WAIT или FUTEX_WAIT_BITSET была прервана сигналом (смотрите signal(7)). В ядрах до версии Linux 2.6.22 эта ошибка также возвращалась при побочном пробуждении; начиная с Linux 2.6.22 этого больше не происходит.

EINVAL

Операция в futex_op является одной из тех, что используют ожидание (timeout), но значение аргумента timeout некорректно (tv_sec меньше нуля или tv_nsec больше 1000000000).

EINVAL

Операция, указанная в futex_op, использует один или оба указателя uaddr и uaddr2, но один из них не указывает на корректный объект, то есть адрес не выровнен по четырёх байтовой границе.

EINVAL

(FUTEX_WAIT_BITSET, FUTEX_WAKE_BITSET) Битовая маска, указанная в val3, равна нулю.

EINVAL

(FUTEX_CMP_REQUEUE_PI) Значение uaddr равно uaddr2 (т. е., предпринята попытка выполнить перемещение в одну и ту же очередь).

EINVAL

(FUTEX_FD) В val указан некорректный номер сигнала.

EINVAL

(FUTEX_WAKE, FUTEX_WAKE_OP, FUTEX_WAKE_BITSET, FUTEX_REQUEUE, FUTEX_CMP_REQUEUE) Ядро обнаружило противоречие между состояние в пользовательском пространстве по адресу uaddr и состоянием в ядре, то есть обнаружило, что ожидающий ждёт посредством операции FUTEX_LOCK_PI на адресе uaddr.

EINVAL

(FUTEX_LOCK_PI, FUTEX_TRYLOCK_PI, FUTEX_UNLOCK_PI) Ядро обнаружило противоречие между состояние в пользовательском пространстве по адресу uaddr и состоянием в ядре. Это указывает на поврежденное значение состояния или что ядро обнаружило ожидающего на адресе uaddr, который делает это посредством операции FUTEX_WAIT или FUTEX_WAIT_BITSET.

EINVAL

(FUTEX_CMP_REQUEUE_PI) Ядро обнаружило противоречие между состояние в пользовательском пространстве по адресу uaddr2 и состоянием в ядре, то есть обнаружило, что ожидающий ждёт посредством операции FUTEX_WAIT или FUTEX_WAIT_BITSET на адресе uaddr2.

EINVAL

(FUTEX_CMP_REQUEUE_PI) Ядро обнаружило противоречие между состояние в пользовательском пространстве по адресу uaddr и состоянием в ядре, то есть обнаружило, что ожидающий ждёт посредством операции FUTEX_WAIT или FUTEX_WAIT_BITESET на адресе uaddr.

EINVAL

(FUTEX_CMP_REQUEUE_PI) Ядро обнаружило противоречие между состояние в пользовательском пространстве по адресу uaddr и состоянием в ядре, то есть обнаружило, что ожидающий ждёт посредством операции FUTEX_LOCK_PI на адресе uaddr (вместо FUTEX_WAIT_REQUEUE_PI).

EINVAL

(FUTEX_CMP_REQUEUE_PI) Предпринята попытка выполнить перемещение ожидающего на фьютекс, отличный от указанного в соответствующем вызове FUTEX_WAIT_REQUEUE_PI для этого вызывающего.

EINVAL

(FUTEX_CMP_REQUEUE_PI) Значение аргумента val не равно 1.

EINVAL

Неверный аргумент.

ENFILE

(FUTEX_FD) Достигнуто ограничение на общее количество открытых файлов в системе.

ENOMEM

(FUTEX_LOCK_PI, FUTEX_TRYLOCK_PI, FUTEX_CMP_REQUEUE_PI) Ядро не может выделить память для хранения информации о состоянии.

ENOSYS

В futex_op задана неверная операция.

ENOSYS

В futex_op был указан параметр FUTEX_CLOCK_REALTIME, но сопутствующая операция не равна FUTEX_WAIT, FUTEX_WAIT_BITSET или FUTEX_WAIT_REQUEUE_PI.

ENOSYS

(FUTEX_LOCK_PI, FUTEX_TRYLOCK_PI, FUTEX_UNLOCK_PI, FUTEX_CMP_REQUEUE_PI, FUTEX_WAIT_REQUEUE_PI) Проверка во время выполнения обнаружила, что операция недоступна. Операции с PI-фьютексами реализованы не на всех архитектурах и не поддерживаются на некоторых моделях ЦП.

EPERM

(FUTEX_LOCK_PI, FUTEX_TRYLOCK_PI, FUTEX_CMP_REQUEUE_PI) Вызывающему запрещено самостоятельно присоединяться к фьютексу по адресу uaddr (для FUTEX_CMP_REQUEUE_PI: фьютексу по адресу uaddr2) (это может быть вызвано повреждением состояния в пользовательском пространстве).

EPERM

(FUTEX_UNLOCK_PI) Вызывающему не принадлежит блокировка, представленная в слове фьютекса.

ESRCH

(FUTEX_LOCK_PI, FUTEX_TRYLOCK_PI, FUTEX_CMP_REQUEUE_PI) Идентификатор нити из слова фьютекса по адресу uaddr не существует.

ESRCH

(FUTEX_CMP_REQUEUE_PI) Идентификатор нити из слова фьютекса по адресу uaddr2 не существует.

ETIMEDOUT

Операция в futex_op использует время ожидания, указанное в timeout, и время истекло до завершения операции.

## ВЕРСИИ
Фьютексы появились в стабильном ядре Linux версии 2.6.0.

Начальная поддержка фьютексов была встроена в Linux 2.5.7, но с другой семантикой, отличающейся от описанной выше. Семантика системного вызова с четырьмя аргументами, описанная в этой странице, появилась в Linux 2.5.40. Пятый аргумент была добавлен в Linux 2.5.70, а шестой аргумент был добавлен в Linux 2.6.7.

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

## ЗАМЕЧАНИЯ
В glibc нет обёртки для данного системного вызова; запускайте его с помощью syscall(2).

На основе фьютексов было реализовано несколько высокоуровневых программных абстракций, например, семафоры POSIX и различные механизмы синхронизации нитей POSIX (мьютексы, переменные условий, блокировки чтения-записи и барьеры).

## ПРИМЕР
В программе, показанной далее, показано использование фьютексов: родительский и дочерний процессы используют пару фьютексов, расположенных в общем анонимном отображении, для синхронизации доступа к общему ресурсу: терминалу. Каждый из процессов записывает nloops (аргумент командной строки, если отсутствует, то 5) сообщений на терминал и использует протокол синхронизации, который гарантирует, что они записываются поочерёдно. Результат работы программы:

```
$ ./futex_demo
Родитель (18534) 0
Потомок  (18535) 0
Родитель (18534) 1
Потомок  (18535) 1
Родитель (18534) 2
Потомок  (18535) 2
Родитель (18534) 3
Потомок  (18535) 3
Родитель (18534) 4
Потомок  (18535) 4
```

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

```
/* futex_demo.c

   Использование: futex_demo [nloops]

                    (по умолчанию: 5)

   Продемонстрировано использование фьютексов в программе, где родитель

   и потомок используют пару фьютексов, расположенных в общем анонимном

   отображении, для синхронизации доступа к общему ресурсу: терминалу.

   Каждый из процессов записывает num-loops на терминал и использует

   протокол синхронизации, который гарантирует, что они выполняют запись

   поочерёдно.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <stdatomic.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <linux/futex.h>
#include <sys/time.h>
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \

                        } while (0)
static int *futex1, *futex2, *iaddr;
static int
futex(int *uaddr, int futex_op, int val,

      const struct timespec *timeout, int *uaddr2, int val3)
{

    return syscall(SYS_futex, uaddr, futex_op, val,

                   timeout, uaddr, val3);
}
/* Получить фьютекс, указанный 'futexp': подождать пока его

   значение не станет 1, и изменить значение на 0. */
static void
fwait(int *futexp)
{

    int s;

    /* atomic_compare_exchange_strong(ptr, oldval, newval)

       атомарно выполняет эквивалент кода:

           if (*ptr == *oldval)

               *ptr = newval;

       Она возвращает true, если тест вернул true и было обновлено *ptr.

    while (1) {

        /* фьютекс доступен? */

        const int zero = 0;

        if (atomic_compare_exchange_strong(futexp, &zero, 1))

            break;      /* да */

        /* фьютекс недоступен, ждём */

        s = futex(futexp, FUTEX_WAIT, 0, NULL, NULL, 0);

        if (s == -1 && errno != EAGAIN)

            errExit("futex-FUTEX_WAIT");

    }
}
/* Освобождаем фьютекс, указанный в 'futexp': если значение фьютекса

   сейчас равно 0, то присваиваем ему 1 и пробуждаем ожидающий фьютекса,

   то есть, если вторая сторона заблокирована в fpost(), то она может

   продолжить работу. */
static void
fpost(int *futexp)
{

    int s;

    /* atomic_compare_exchange_strong() описан в комментария выше */

    const int one = 1;

    if (atomic_compare_exchange_strong(futexp, &one, 0)) {

        s = futex(futexp, FUTEX_WAKE, 1, NULL, NULL, 0);

        if (s  == -1)

            errExit("futex-FUTEX_WAKE");

    }
}
int
main(int argc, char *argv[])
{

    pid_t childPid;

    int j, nloops;

    setbuf(stdout, NULL);

    nloops = (argc > 1) ? atoi(argv[1]) : 5;

    /* Создаём общее анонимное отображение, в котором будем хранить

       фьютексы. Так как фьютексы совместно используются процессами,

       воспользуемся операциями с «общими» фьютексами (т. е., без

       суффикса «_PRIVATE»). */

    iaddr = mmap(NULL, sizeof(int) * 2, PROT_READ | PROT_WRITE,

                MAP_ANONYMOUS | MAP_SHARED, -1, 0);

    if (iaddr == MAP_FAILED)

        errExit("mmap");

    futex1 = &iaddr[0];

    futex2 = &iaddr[1];

    *futex1 = 0;        /* Состояние: недоступен */

    *futex2 = 1;        /* Состояние: доступен */

    /* Создаём дочерний процесс, который наследует общее анонимное

       отображение. */

    childPid = fork();

    if (childPid == -1)

        errExit("fork");

    if (childPid == 0) {        /* Child */

        for (j = 0; j < nloops; j++) {

            fwait(futex1);

            printf("Потомок  (%ld) %d\n", (long) getpid(), j);

            fpost(futex2);

        }

        exit(EXIT_SUCCESS);

    }

    /* предок попадает сюда */

    for (j = 0; j < nloops; j++) {

        fwait(futex2);

        printf("Родитель (%ld) %d\n", (long) getpid(), j);

        fpost(futex1);

    }

    wait(NULL);

    exit(EXIT_SUCCESS);
}
```

## СМОТРИТЕ ТАКЖЕ
get_robust_list(2), restart_syscall(2), pthread_mutexattr_getprotocol(3), futex(7), sched(7)

Файлы из дерева исходного кода ядра:

- Documentation/pi-futex.txt

- Documentation/futex-requeue-pi.txt

- Documentation/locking/rt-mutex.txt

- Documentation/locking/rt-mutex-design.txt

- Documentation/robust-futex-ABI.txt

Franke, H., Russell, R., and Kirwood, M., 2002. Fuss, Futexes and Furwocks: Fast Userlevel Locking in Linux (доклад на симпозиуме по Linux в 2002 году),

http://kernel.org/doc/ols/2002/ols2002-pages-479-495.pdf

Hart, D., 2009. A futex overview and update, http://lwn.net/Articles/360699/

Hart, D. и Guniguntala, D., 2009. Requeue-PI: Making Glibc Condvars PI-Aware (доклад на Real-Time Linux Workshop в 2009 году), http://lwn.net/images/conf/rtlws11/papers/proc/p10.pdf

Drepper, U., 2011. Futexes Are Tricky, http://www.akkadia.org/drepper/futex.pdf

Пример библиотеки futex, futex-*.tar.bz2, доступен на

ftp://ftp.kernel.org/pub/linux/kernel/people/rusty/


futimesat

package: man-pages-ru

title: futimesat(2)

text:
# futimesat(2)

## ИМЯ
futimesat - изменяет временные отметки файла, определяемого относительно файлового дескриптора каталога

## ОБЗОР

```
#include <fcntl.h> /* определения констант AT_* */
#include <sys/time.h>
```

```
int futimesat(int dirfd, const char *pathname,
              const struct timeval times[2]);
```

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

futimesat(): _GNU_SOURCE

## ОПИСАНИЕ
Данный системный вызов устарел. Используйте вместо него utimensat(2).

Системный вызов futimesat() работает также как системный вызов utimes(2), за исключением случаев, описанных в данной справочной странице.

Если в pathname задан относительный путь, то он считается относительно каталога, на который ссылается файловый дескриптор dirfd (а не относительно текущего рабочего каталога вызывающего процесса, как это делается в utimes(2)).

Если в pathname задан относительный путь и dirfd равно специальному значению AT_FDCWD, то pathname рассматривается относительно текущего рабочего каталога вызывающего процесса (как utimes(2)).

Если в pathname задан абсолютный путь, то dirfd игнорируется.

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

## ОШИБКИ
В futimesat() могут возникнуть те же ошибки, что и в utimes(2). Также, в futimesat() могут возникнуть следующие ошибки:

EBADF

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

ENOTDIR

Значение pathname содержит относительный путь и dirfd содержит файловый дескриптор, указывающий на файл, а не на каталог.

## ВЕРСИИ
Вызов futimesat() был добавлен в ядро Linux версии 2.6.16; поддержка в glibc доступна с версии 2.4.

## СООТВЕТСТВИЕ СТАНДАРТАМ
Данный системный вызов не является стандартным. Он был реализован по спецификации POSIX.1, но она была заменена на utimensat(2).

Подобный системный вызов есть в Solaris.

## ЗАМЕЧАНИЯ

### Замечания по glibc
Если pathname равно NULL, то обёрточная функция glibc futimesat() обновляет временные метки файла, указанного в dirfd.

## СМОТРИТЕ ТАКЖЕ
stat(2), utimensat(2), utimes(2), futimes(3), path_resolution(7)


title: get_kernel_syms(2)

text:
# get_kernel_syms(2)

## ИМЯ
get_kernel_syms - получить экспортируемые символы ядра и модулей

## ОБЗОР

```
#include <linux/module.h>
```

```
int get_kernel_syms(struct kernel_sym *table);
```

Замечание: В заголовочных файлах glibc этой системный вызов отсутствует; смотрите ЗАМЕЧАНИЯ.

## ОПИСАНИЕ
Замечание: Данный системный вызов доступен только в ядрах до Linux 2.6.

Если table равно NULL, то get_kernel_syms() возвращает количество символов доступных для запроса. Иначе таблица заполняется структурами:

```
struct kernel_sym {

    unsigned long value;

    char          name[60];
};
```

Символы вида #module-name представляют собой ссылки на модули. Значение, связанное с таким символом, содержит адрес, по которому загружен модуль.

К символам, экспортируемым из модуля, добавляется метка модуля, а модули возвращаются в обратном порядке, в котором были загружены.

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

## ОШИБКИ
Может возвращаться только одна ошибка:

ENOSYS

Вызов get_kernel_syms() не поддерживается в этой версии ядра.

## ВЕРСИИ
Данный системный вызов есть только в Linux до версии 2.4; он был удалён в Linux 2.6.

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

## ЗАМЕЧАНИЯ
Устаревший системный вызов, не поддерживается glibc. В заголовочных файлах glibc он не объявлен, но в недавнем прошлом версии glibc до 2.23 экспортировали ABI для этого системного вызова. Поэтому, чтобы получить данный системный вызов достаточно вручную объявить интерфейс в своём коде; или же можно вызвать его через syscall(2).

## ДЕФЕКТЫ
Нет способа указать размер буфера, выделенного для table. Если символы были добавлены в ядро после того, как программа запросила размер таблицы символов, то это вызовет повреждение данных в памяти.

Длина имён экспортируемых символов ограничена 59 знаками.

Из-за этих ограничений вместо данного системного вызова рекомендуется использовать query_module(2) (который, в настоящее время, тоже устарел и заменён на другие интерфейсы, перечисленные в конце этой справочной страницы).

## СМОТРИТЕ ТАКЖЕ
create_module(2), delete_module(2), init_module(2), query_module(2)


title: get_mempolicy(2)

text:
# get_mempolicy(2)

## ИМЯ
get_mempolicy - возвращает политику работы с памятью NUMA для нити

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

```
long get_mempolicy(int *mode, unsigned long *nodemask,
                  unsigned long maxnode, void *addr,
                  unsigned long flags);
```

```
Компонуется при указании параметра -lnuma.
```

## ОПИСАНИЕ
Вызов get_mempolicy() возвращает политику NUMA вызывающей нити или адреса памяти (в зависимости от значения flags).

Машина с NUMA имеет различные контроллеры памяти с различными расстояниями до определённых ЦП. Политикой памяти задаётся узел, на котором выделяется память для нити.

Если значение flags равно 0, то в буферы, указанные в mode и nodemask, возвращается информация о политике по умолчанию для вызывающей нити (которая была задана с помощью set_mempolicy(2)). Полученное значение может использоваться для восстановления политики нити в её состояние на время вызова get_mempolicy() с помощью set_mempolicy(2). Если значение flags равно 0, то значение addr должно быть равно NULL.

Если flags равно MPOL_F_MEMS_ALLOWED (доступно, начиная с Linux 2.6.24), то аргумент mode игнорируется и набор узлов (их памяти), которые разрешено указывать нити в последующих вызовах mbind(2) или set_mempolicy(2) (в отсутствии любых значений флагов режима), возвращается в nodemask. Не разрешено объединять MPOL_F_MEMS_ALLOWED с MPOL_F_ADDR или MPOL_F_NODE.

Если flags равно MPOL_F_ADDR, то возвращается информация об управляющей политике адреса памяти, указанного в addr. Эта политика может отличаться от политики нити по умолчанию, если mbind(2) или одна из вспомогательных функций, описанных в numa(3), были использованы при установлении политики для диапазона памяти, содержащего addr.

Если аргумент mode не равен NULL, то get_mempolicy() сохранит режим политики и все необязательные флаги режима запрашиваемой политики NUMA в место, указанное этим аргументом. Если nodemask не равно NULL, то значение nodemask, связанной с политикой, будет сохранено в место, указанное этим аргументом. В maxnode задаётся количество идентификаторов узлов, которые могут быть сохранены в nodemask — то есть, максимальный идентификатор узла плюс один. Значение, указанное в maxnode, всегда округляется до кратного sizeof(unsigned long)*8.

Если в flags указано MPOL_F_NODE и MPOL_F_ADDR, то get_mempolicy() вернёт идентификатор узла, на котором расположен адрес addr в расположение, заданное mode. Если для указанного адреса страница ещё не выделена, то get_mempolicy() выделит страницу, как если бы нить выполнила чтение (загрузку) по этому адресу, и вернёт идентификатор узла, на котором была размещена страница.

Если flags содержит MPOL_F_NODE, но не MPOL_F_ADDR, и значение текущей политики нити равно MPOL_INTERLEAVE, то get_mempolicy() вернёт в расположение, указанное в аргументе mode (не равно NULL), идентификатор узла следующего узла, который будет использован при чередовании внутренних страниц ядра, выделяемых для нити. Эти выделения содержат страницы памяти отображённых файлов в диапазоне памяти процесса, отображённых с помощью вызова mmap(2) с флагом MAP_PRIVATE для чтения, и в диапазонах памяти, отображённых с флагом MAP_SHARED, для всех операций.

Другие значения флагов зарезервированы.

Обзор возможных политик смотрите в set_mempolicy(2).

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

## ОШИБКИ
EFAULT

Часть всего диапазона памяти, заданная в nodemask и maxnode, указывает за пределы доступного адресного пространства.

EINVAL

Значение, указанное в maxnode, меньше количества идентификаторов узлов, поддерживаемых системой. Или в flags указаны значения, отличные от MPOL_F_NODE или MPOL_F_ADDR; или в flags указано MPOL_F_ADDR и addr равно NULL, или в flags не указано MPOL_F_ADDR и addr не равно NULL. Или в flags указано MPOL_F_NODE, но не MPOL_F_ADDR и значение текущей политики нити не равно MPOL_INTERLEAVE. Или в flags указано MPOL_F_MEMS_ALLOWED вместе с MPOL_F_ADDR или MPOL_F_NODE (и есть другие случаи возврата EINVAL).

## ВЕРСИИ
Системный вызов get_mempolicy() был добавлен в ядро Linux версии 2.6.7.

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

## ЗАМЕЧАНИЯ
Информация о библиотеке доступна в numa(7).

## СМОТРИТЕ ТАКЖЕ
getcpu(2), mbind(2), mmap(2), set_mempolicy(2), numa(3), numa(7), numactl(8)


title: get_robust_list(2)

summary: возвращает/назначает список надёжных

text:
# get_robust_list(2)

## ИМЯ
get_robust_list, set_robust_list - возвращает/назначает список надёжных фьютексов (futexes)

## ОБЗОР

```
#include <linux/futex.h>
#include <sys/types.h>
#include <syscall.h>
```

```
long get_robust_list(int pid, struct robust_list_head **head_ptr,
                     size_t *len_ptr);
long set_robust_list(struct robust_list_head *head, size_t len);
```

Замечание: В glibc нет обёрточных функций для этих системных вызовов; смотрите ЗАМЕЧАНИЯ.

## ОПИСАНИЕ
Данные системные вызовы служат для ведения понетевых списков надёжных фьютексов. Данные списки управляются из пользовательского пространства: ядро знает только расположение начала списка. Нить может информировать ядро о расположении своего списка надёжных фьютексов с помощью set_robust_list(). Адрес списка надёжных фьютексов нити можно получить с помощью get_robust_list().

Предназначением списка надёжных фьютексов является гарантия того, что если нить неожиданно из-за ошибки не разблокирует фьютекс перед завершением или вызовом execve(2), другая ожидающая этот фьютекс нить получит уведомление о том, что бывший владелец фьютекса прекратил работу. Данное уведомление состоит из двух частей: установленного бита FUTEX_OWNER_DIED в слове фьютекса и выполнение ядром futex(2) с операцией FUTEX_WAKE для одной из нитей, ожидающих фьютекс.

Системный вызов get_robust_list() возвращает начало списка надёжных фьютексов нити, идентификатор которой указан в pid. Если значение pid равно 0, то возвращается начало списка вызывающей нити. Начало списка сохраняется в расположение, указанное head_ptr. Размер объекта, указываемый **head_ptr, сохраняется в len_ptr.

Право вызывать get_robust_list() определяется проверкой режима доступа ptrace PTRACE_MODE_READ_REALCREDS; смотрите ptrace(2).

Системный вызов set_robust_list() запрашивает ядро записать начало списка надёжных фьютексов, принадлежащего вызывающей нити. Аргумент head содержит начало списка для записи. Аргумент len должен быть равен sizeof(*head).

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
Системные вызовы set_robust_list() и get_robust_list() возвращают ноль при успешном выполнении и код ошибки в противном случае.

## ОШИБКИ
Системный вызов pthread_setcancelstate() может завершиться со следующей ошибкой:

EINVAL

Значение len не равно sizeof(struct robust_list_head).

Системный вызов get_robust_list() может завершиться со следующими ошибками:

EFAULT

Начало списка надёжных фьютексов невозможно сохранить в расположение head.

EPERM

Вызывающий процесс не имеет прав на просмотр списка надёжных фьютексов нити с идентификатором pid и не имеет мандата CAP_SYS_PTRACE.

ESRCH

Нить с идентификатором pid не найдена.

## ВЕРСИИ
Данные системные вызовы были добавлены в Linux 2.6.17.

## ЗАМЕЧАНИЯ
Эти системные вызовы не нужны обычным приложениям. Поддержка в glibc отсутствует. В маловероятном случае, когда вы хотите вызвать их напрямую, используйте syscall(2).

В нити может быть только один список надёжных фьютексов; поэтому приложения, которым требуется данное свойство, должны использовать мьютексы, предоставляемые glibc.

В первоначальной реализации нить, ожидающая фьютекс, уведомлялась о кончине владельца только, если владелец прекращал работу. Начиная с Linux 2.6.28 уведомление также посылается при выполнении владельцем execve(2).

Идентификаторы нитей, упоминаемые в основном тексте, являются ядерными идентификаторами нити, которые возвращаются из clone(2) и gettid(2).

## СМОТРИТЕ ТАКЖЕ
futex(2), pthread_mutexattr_setrobust(3)

Файлы Documentation/robust-futexes.txt и Documentation/robust-futex-ABI.txt в дереве исходного кода ядра Linux


getcpu

title: getcpu(2)

text:
# getcpu(2)

## ИМЯ
getcpu - определяет ЦП и узел NUMA, на котором выполняется вызывающая нить

## ОБЗОР

```
#include <linux/getcpu.h>
```

```
int getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache);
```

## ОПИСАНИЕ
Системный вызов getcpu() определяет процессор и узел, на котором вызывающая нить или процесс выполняются в данный момент и записывает их в виде целых чисел в память, на которую указывают аргументы cpu и node. Процессор представляется в виде уникального малого целого числа, закреплённого за определённым ЦП. Узел представляется в виде уникального идентификатора, закреплённого за определённым узлом NUMA. Если значение cpu или node равно NULL, то по соответствующему указателю ничего не записывается.

Третий аргумент этого системного вызова в настоящее время не используется и указываться как NULL, не требуется переносимость на Linux 2.6.23 или более младшие версии (смотрите ЗАМЕЧАНИЯ).

Информация, помещаемая в cpu, будет находиться там только на время вызова: unless the CPU affinity has been fixed using sched_setaffinity(2), the kernel might change the CPU at any time. (Normally this does not happen because the scheduler tries to minimize movements between CPUs to keep caches hot, but it is possible.) Достоверность информации, помещаемой в cpu, гарантируется только на момент вызова: если привязка ЦП не была изменена с помощью sched_setaffinity(2), то ядро может сменить ЦП в любой момент (обычно этого не происходит, так как планировщик пытается минимизировать перемещения задач между процессорами для поддержания актуальности кэша,но всё же это возможно). Вызывающий должен быть готов к ситуации, что информация, возвращённая в cpu и node, может потерять актуальность уже после возврата из вызова.

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

## ОШИБКИ
EFAULT

Аргументы указывают за пределы адресного пространства вызывающего процесса.

## ВЕРСИИ
Системный вызов getcpu() добавлен в ядре 2.6.19 для x86-64 и i386. Библиотечная поддержка добавлена в glibc 2.29 (ранние версии glibc не содержали обёрточную функцию для этого вызова, нужно было использовать syscall(2)).

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

## ЗАМЕЧАНИЯ
Linux старается выполнить данный вызов как можно быстрее (на некоторых архитектурах это делается через реализацию в vdso(7)). Предназначение getcpu() — позволить программам оптимизировать обработку данных на разных ЦП или выполнить оптимизации NUMA.

Аргумент tcache не используется начиная с Linux 2.6.24. В более старых ядрах, если этот аргумент не равнялся NULL, то в нём задавался указатель на буфер, выделяемый вызывающим в локальном хранилище нити, который использовался для работы механизма кэширования getcpu(). Использование кэша могло бы увеличить скорость работы getcpu(), и расплатой за это было бы возникновение очень маленькой вероятности, что возвращаемая информация устарела. Кэширующий механизм стал рассматриваться как вызывающий проблемы при перемещения нитей между ЦП, и поэтому теперь этот аргумент игнорируется.

## СМОТРИТЕ ТАКЖЕ
mbind(2), sched_setaffinity(2), set_mempolicy(2), sched_getcpu(3), cpuset(7), vdso(7)


getdents

title: getdents(2)

summary: возвращает записи каталога

text:
# getdents(2)

## ИМЯ
getdents, getdents64 - возвращает записи каталога

## ОБЗОР

```
int getdents(unsigned int fd, struct linux_dirent *dirp,
             unsigned int count);
int getdents64(unsigned int fd, struct linux_dirent64 *dirp,
             unsigned int count);
```

Замечание: В glibc нет обёрточных функций для этих системных вызовов; смотрите ЗАМЕЧАНИЯ.

## ОПИСАНИЕ
Это не те функции, которые должны представлять для вас интерес. Смотрите описание функции readdir(3), которая является интерфейсом библиотеки языка C, соответствующим стандарту POSIX. В этой странице описаны минимальные интерфейсы системных вызовов ядра.

### getdents()
Системный вызов getdents() читает несколько структур linux_dirent из каталога, на который указывает открытый файловый дескриптор fd, в буфер, указанный в dirp. В аргументе count задаётся размер этого буфера.

Структура linux_dirent определена следующим образом:

```
struct linux_dirent {

    unsigned long  d_ino;     /* номер иноды */

    unsigned long  d_off;     /* смещение до следующей linux_dirent */

    unsigned short d_reclen;  /* длина этой linux_dirent */

    char           d_name[];  /* имя файла (в конце null) */

                      /* реальная длина (d_reclen - 2 -

                         offsetof(struct linux_dirent, d_name)) */

    /*

    char           pad;       // нулевой байт заполнения

    char           d_type;    // тип файла (только начиная с Linux

                              // 2.6.4); смещение (d_reclen - 1)

    */
}
```

В d_ino указан номер inode. В d_off задаётся расстояние от начала каталога до начала следующей linux_dirent. В d_reclen указывается размер данного linux_dirent целиком. В d_name задаётся имя файла, завершающееся null.

d_type — байт в конце структуры, которым определяется тип файла. В нём содержится одно из следующих значений (определённых в <dirent.h>):

DT_BLK

Блочное устройство.

DT_CHR

Символьное устройство.

DT_DIR

Каталог.

DT_FIFO

Именованный канал (FIFO).

DT_LNK

Символическая ссылка.

DT_REG

Обычный файл.

DT_SOCK

Доменный сокет UNIX.

DT_UNKNOWN

Неизвестный тип.

Поле d_type появилось начиная с Linux 2.6.4. Оно занимает пространство, которое раньше в структуре linux_dirent было отведено для заполняющего байта с нулевым значением. Поэтому при работе с ядрами до версии 2.6.3 включительно при чтении значения этого поля всегда возвращается 0 (DT_UNKNOWN).

В настоящее время, только файловые системы (среди которых: Btrfs, ext2, ext3 и ext4) поддерживают возврат типа файла в d_type. Все приложения должны правильно обрабатывать возвращаемое значение DT_UNKNOWN.

### getdents64()
Первоначальный системный вызов Linux getdents() не работал с файловыми системами большого размера и большими смещениями файлов. В связи с этим, в Linux 2.4 была добавлен getdents64(), с более широкими типами полей d_ino и d_off. Также getdents64() поддерживает явно указанное поле d_type.

Системный вызов getdents64() подобен getdents(), за исключением того, что второй аргумент является указателем на буфер, содержащий структуры следующего типа:

```
struct linux_dirent64 {

    ino64_t        d_ino;    /* 64-битный номер иноды */

    off64_t        d_off;    /* 64-битное смещение следующей структуры */

    unsigned short d_reclen; /* размер этой dirent */

    unsigned char  d_type;   /* тип файла */

    char           d_name[]; /* имя файла (в конце null) */
};
```

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

## ОШИБКИ
EBADF

Неверный файловый дескриптор fd.

EFAULT

Аргумент указывает за пределы адресного пространства вызывающего процесса.

EINVAL

Буфер результата слишком мал.

ENOENT

Заданный каталог не существует.

ENOTDIR

Файловый дескриптор указывает не на каталог.

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

## ЗАМЕЧАНИЯ
В glibc нет обёртки для данных системных вызовов; запускайте их с помощью syscall(2). Структуру linux_dirent или linux_dirent64 нужно определить самостоятельно. Однако лучше использовать readdir(3).

Данные системные вызовы заместил readdir(2).

## ПРИМЕР
В программе, показанной далее, демонстрируется использование getdents(). В следующем выводе показан пример запуска этой программы с каталогом с ext2:

```
$ ./a.out /testfs/
--------------- nread=120 ---------------
inode#    file type  d_reclen  d_off   d_name

       2  directory    16         12  .

       2  directory    16         24  ..

      11  directory    24         44  lost+found

      12  regular      16         56  a

  228929  directory    16         68  sub

   16353  directory    16         80  sub2

  130817  directory    16       4096  sub3
```

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

```
#define _GNU_SOURCE
#include <dirent.h>     /* Определяет константы DT_* */
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#define handle_error(msg) \

        do { perror(msg); exit(EXIT_FAILURE); } while (0)
struct linux_dirent {

    long           d_ino;

    off_t          d_off;

    unsigned short d_reclen;

    char           d_name[];
};
#define BUF_SIZE 1024
int
main(int argc, char *argv[])
{

    int fd, nread;

    char buf[BUF_SIZE];

    struct linux_dirent *d;

    int bpos;

    char d_type;

    fd = open(argc > 1 ? argv[1] : ".", O_RDONLY | O_DIRECTORY);

    if (fd == -1)

        handle_error("open");

    for ( ; ; ) {

        nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);

        if (nread == -1)

            handle_error("getdents");

        if (nread == 0)

            break;

        printf("--------------- nread=%d ---------------\n", nread);

        printf("inode#    file type  d_reclen  d_off   d_name\n");

        for (bpos = 0; bpos < nread;) {

            d = (struct linux_dirent *) (buf + bpos);

            printf("%8ld  ", d->d_ino);

            d_type = *(buf + bpos + d->d_reclen - 1);

            printf("%-10s ", (d_type == DT_REG) ?  "regular" :

                             (d_type == DT_DIR) ?  "directory" :

                             (d_type == DT_FIFO) ? "FIFO" :

                             (d_type == DT_SOCK) ? "socket" :

                             (d_type == DT_LNK) ?  "symlink" :

                             (d_type == DT_BLK) ?  "block dev" :

                             (d_type == DT_CHR) ?  "char dev" : "???");

            printf("%4d %10lld  %s\n", d->d_reclen,

                    (long long) d->d_off, d->d_name);

            bpos += d->d_reclen;

        }

    }

    exit(EXIT_SUCCESS);
}
```

## СМОТРИТЕ ТАКЖЕ
readdir(2), readdir(3), inode(7)


getdomainname

title: getdomainname(2)

summary: получить/установить имя домена NIS

text:
# getdomainname(2)

## ИМЯ
getdomainname, setdomainname - получить/установить имя домена NIS

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

int getdomainname(char *name, size_t len);

int setdomainname(const char *name, size_t len);

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

getdomainname(), setdomainname():

```
    начиная с 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)
```

## ОПИСАНИЕ
Данные функции используются для получения или изменения имени домена NIS узла системы. Точнее говоря, они работают с именем домена NIS, связанным с пространством имён UTS вызывающего процесса.

setdomainname() изменяет доменное имя на значение, указанное в массиве символов name. В аргументе len задаётся количество байт в name. (То есть name может не завершаться байтом с null.)

getdomainname() возвращает доменное имя с null на конце в массиве символов name, который имеет длину len байт. Если для доменного имени с null на конце требуется больше чем len байт, то getdomainname() возвращает первые len байт (glibc) или возвращает ошибку (libc).

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

## ОШИБКИ
setdomainname() может завершиться со следующими ошибками:

EFAULT

name указывает за пределы пользовательского адресного пространства.

EINVAL

Значение len отрицательно или слишком большое.

EPERM

У вызывающего нет мандата CAP_SYS_ADMIN в пользовательском пространстве имён, связанном с его пространством имён UTS (смотрите namespaces(7)).

getdomainname() может завершиться со следующими ошибками:

EINVAL

Для getdomainname() в libc: значение name равно NULL или name длиннее чем len байт.

## СООТВЕТСТВИЕ СТАНДАРТАМ
В POSIX нет этих вызовов.

## ЗАМЕЧАНИЯ
Начиная с Linux 1.0, длина доменного имени, включая завершающий байт с null, ограничена 64 байтами. В более старых ядрах ограничение было 8 байт.

На большинстве архитектур Linux (включая x86), системный вызов getdomainname() отсутствует; вместо него в библиотеке glibc реализована функция getdomainname(), которая возвращает копию поля domainname, которую возвращает вызов uname(2).

## СМОТРИТЕ ТАКЖЕ
gethostname(2), sethostname(2), uname(2), uts_namespaces(7)


getgid

title: getgid(2)

summary: получить идентификатор группы процесса

text:
# getgid(2)

## ИМЯ
getgid, getegid - получить идентификатор группы процесса

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

\#include <sys/types.h>

gid_t getgid(void);

gid_t getegid(void);

## ОПИСАНИЕ
getgid() возвращает действительный идентификатор группы вызывающего процесса.

getegid() возвращает эффективный идентификатор группы вызывающего процесса.

## ОШИБКИ
Функции всегда завершаются успешно.

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

## ЗАМЕЧАНИЯ
Первоначальные версии системных вызовов getgid() и getegid() в Linux поддерживали только 16-битные идентификаторы групп. Позднее в Linux 2.4 были добавлены вызовы getgid32() и getegid32(), поддерживающие 32-битные идентификаторы. В glibc обёрточные функции getgid() и getegid() работают одинаково вне зависимости от версий ядра.

На Alpha вместо пары системных вызовов getgid() и getegid() предоставляется один getxgid(), который возвращает пару реальный и эффективный GID. Обёрточные функции glibc getgid() и getegid() скрывают это. Подробности об отображении регистров смотрите в syscall(2).

## СМОТРИТЕ ТАКЖЕ
getresgid(2), setgid(2), setregid(2), credentials(7)


getgroups

title: getgroups(2)

text:
# getgroups(2)

## ИМЯ
getgroups, setgroups - получить/установить список дополнительных идентификаторов групп

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

\#include <unistd.h>

int getgroups(int size, gid_t list[]);

\#include <grp.h>

int setgroups(size_t size, const gid_t *list);

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

setgroups(): Начиная с glibc 2.19: _DEFAULT_SOURCE В версии Glibc 2.19 и более ранних: _BSD_SOURCE

## ОПИСАНИЕ
Вызов getgroups() возвращает идентификаторы дополнительных групп вызывающего процесса в списке list. В аргументе size должно быть указано максимальное количество элементов, которые можно сохранить в буфер, указанный в list. Если вызывающий процесс является членом в более чем size дополнительных групп, то возвращается ошибка.

Не определено, будет ли в этот список включён эффективный идентификатор группы вызывающего процесса (то есть приложение также должно вызвать getegid(2) и добавить или удалить полученное значение).

Если размер size равен нулю, то список list не изменяется, а просто возвращается общее количество идентификаторов дополнительных групп процесса. Это позволяет вызывающему определить размер динамически выделяемого списка list, который будет использоваться при повторном вызове getgroups().

Вызов setgroups() устанавливает идентификаторы дополнительных групп для вызывающего процесса. Для работы требуются права (смотрите описание ошибки EPERM ниже). В аргументе size задаётся количество дополнительных идентификаторов групп в буфере, указанном list. Процесс может выйти из всех дополнительных группы вызвав:

```
setgroups(0, NULL);
```

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

При успешном выполнении setgroups() возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
EFAULT

Значение list является неправильным адресом.

Вызов getgroups() также может завершиться со следующей ошибкой:

EINVAL

Значение size меньше чем количество дополнительных идентификаторов групп, но не ноль.

Вызов setgroups() также может завершиться со следующими ошибками:

EINVAL

Значение size больше чем NGROUPS_MAX (32, до Linux 2.6.4; 65536, начиная с Linux 2.6.4).

ENOMEM

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

EPERM

Вызывающий процесс не имеет достаточно прав (вызывающий не имеет мандата CAP_SETGID в пользовательском пространстве имён, в котором он находится).

EPERM (начиная с Linux 3.19)

Использование setgroups() запрещено в этом пространстве имён user. Смотрите описание /proc/[pid]/setgroups в user_namespaces(7).

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

setgroups(): SVr4, 4.3BSD. Так как для setgroups() требуются права, она не описана в POSIX.1.

## ЗАМЕЧАНИЯ
Процесс может иметь, как минимум, NGROUPS_MAX дополнительных идентификаторов групп в дополнении к эффективному идентификатору группы. Константа NGROUPS_MAX определена в <limits.h>. Список дополнительных идентификаторов групп наследуется из родительского процесса и сохраняется при вызове execve(2).

Максимальное количество дополнительных идентификаторов групп можно выяснить с помощью sysconf(3):

```
long ngroups_max;
ngroups_max = sysconf(_SC_NGROUPS_MAX);
```

Максимальное значение, возвращаемое getgroups(), не может быть больше чем на единицу значения, полученного данным способом. Начиная с Linux 2.6.4, максимальное количество идентификаторов дополнительных групп также видимо через специальный файл Linux, доступный только для чтения — /proc/sys/kernel/ngroups_max.

Первоначальная версия системного вызова getgroups() в Linux поддерживала только 16-битные идентификаторы групп. Позднее в Linux 2.4 был добавлен вызов getgroups32(), поддерживающий 32-битные идентификаторы. В glibc обёрточная функция getgroups() работает одинаково вне зависимости от версий ядра.

### Отличия между библиотекой C и ядром
На уровне ядра ID пользователя и группы являются атрибутами нити. Однако в POSIX требуется, чтобы все нити в процессе имели одинаковые права. В реализации нитей NPTL требования POSIX реализованы через обёрточные функции для различных системных вызовов, которые изменяют UID и GID процесса. В этих функциях (включая и для setgroups()) используется алгоритмы на основе сигналов, которые следят за тем, что когда у одной нити изменяются права, эти изменения выполняются и для остальных нитей процесса. Подробное описание смотрите в nptl(7).

## СМОТРИТЕ ТАКЖЕ
getgid(2), setgid(2), getgrouplist(3), group_member(3), initgroups(3), capabilities(7), credentials(7)


gethostname

title: gethostname(2)

summary: получить/установить имя узла

text:
# gethostname(2)

## ИМЯ
gethostname, sethostname - получить/установить имя узла

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

int gethostname(char *name, size_t len);

int sethostname(const char *name, size_t len);

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

gethostname():

Начиная с glibc 2.12: _BSD_SOURCE || _XOPEN_SOURCE >= 500

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

sethostname():

```
    начиная с 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)
```

## ОПИСАНИЕ
Данные системные вызовы используются для получения или изменения имени узла системы. Точнее говоря, они работают с именем узла, связанным с пространством имён UTS вызывающего процесса.

Вызов sethostname() устанавливает имя узла равны значению, указанному в массиве символов name. Аргумент len определяет количество байт в name. (Таким образом, name не требует наличия завершающего байта с null.)

gethostname() возвращает имя узла с null на конце в массиве символов name длиной len байт. Если имя узла, оканчивающееся null, не помещается, то имя обрезается и ошибки не происходит (но смотрите ЗАМЕЧАНИЯ далее). В POSIX.1 сказано, что если обрезание произошло, то неясно, будет ли буфер содержать завершающий байт с null.

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

## ОШИБКИ
EFAULT

name является неправильным адресом.

EINVAL

len имеет отрицательное значение или для sethostname() длина len больше, чем максимально допустимое значение.

ENAMETOOLONG

(gethostname() из glibc) len меньше чем реальный размер. (До версии 2.1, glibc возвращала в этом случае EINVAL.)

EPERM

Для работы с sethostname() у вызывающего нет мандата CAP_SYS_ADMIN в пользовательском пространстве имён, связанном с его пространством имён UTS (смотрите namespaces(7)).

## СООТВЕТСТВИЕ СТАНДАРТАМ
SVr4, 4.4BSD (данная функция впервые появилась в 4.2BSD). В POSIX.1-2001 и POSIX.1-2008 определена gethostname(), но нет sethostname().

## ЗАМЕЧАНИЯ
SUSv2 гарантирует, что «Длина имени узла ограничена 255-ю байтами». POSIX.1 гарантирует, что «Длина имени узла (не включая завершающий нулевой символ) ограничена HOST_NAME_MAX байтами». В Linux значение HOST_NAME_MAX равно 64, которое было урезано начиная с Linux 1.0 (ранние версии имели предел в 8 байт).

### Отличия между библиотекой C и ядром
Библиотека GNU C library не использует системный вызов gethostname(); вместо этого gethostname() в ней реализован в виде библиотечной функции, которая вызывает uname(2) и копирует до len байт в name из возвращаемого поля nodename. Выполнив копирование, функция проверяет, что длина nodename не больше или равна len, и если это обнаруживается, то функция возвращает -1, устанавливая значение errno равным ENAMETOOLONG; в этом случае в возвращаемое значение name завершающий null не добавляется.

Версии glibc до 2.2 обрабатывали случай превышения длины nodename по другому: ничего не копировалось в name и функция возвращала -1, устанавливая errno равным ENAMETOOLONG.

## СМОТРИТЕ ТАКЖЕ
hostname(1), getdomainname(2), setdomainname(2), uname(2), uts_namespaces(7)


getitimer

title: getitimer(2)

text:
# getitimer(2)

## ИМЯ
getitimer, setitimer - считывает или устанавливает значение таймера интервалов

## ОБЗОР

```
#include <sys/time.h>
```

```
int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimerval *new_value,
              struct itimerval *old_value);
```

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

В аргументе which можно задать три типа таймеров, каждый выполняет отсчёт по разным часам и генерирует разный сигнал по истечении срока:

ITIMER_REAL

Этот таймер отсчитывается по реальному времени (то есть обычному). По каждому истечению выдаёт сигнал SIGALRM.

ITIMER_VIRTUAL

Этот таймер отсчитывается по времени ЦП в пользовательском режиме, проведённым процессом (учёт включает время ЦП, потреблённое всеми нитями процесса). По каждому истечению выдаёт сигнал SIGVTALRM.

ITIMER_PROF

Этот таймер отсчитывается по полному времени ЦП, потраченному процессом (учёт включает время ЦП, потреблённое всеми нитями процесса). По каждому истечению выдаёт сигнал SIGPROF.

Данный таймер вместе с ITIMER_VIRTUAL можно использовать для профилирования затрат процессом системного и пользовательского времени ЦП.

Процесс может иметь только по одному таймеру каждого типа.

Величина, на которую устанавливается таймер, определяется следующими структурами:

```
struct itimerval {

    struct timeval it_interval; /* интервал для периодического таймера */

    struct timeval it_value;    /* время до следующего окончания */
};
struct timeval {

    time_t      tv_sec;     /* секунды */

    suseconds_t tv_usec;    /* микросекунды */
};
```

### getitimer()
Функция getitimer() помещает текущее значение таймера, указанного в which, в буфер, указанный в curr_value.

Вложенная структура it_value содержит количество оставшегося времени до следующего истечения таймера. Это значение изменяется после начала отсчёта таймера и будет сброшено в it_interval при истечении таймера. Если оба поля it_value равны нулю, то это означает что таймер выключен (неактивен).

Вложенная структура it_interval содержит интервал таймера. Если оба поля it_intervalравны нулю, то это указывает на одноразовый таймер (то срабатывающий один раз).

### setitimer()
Функция setitimer() настраивает таймер which значением new_value. Если значение old_value не NULL, то оно указывает на буфер, в который сохраняется предыдущее значение таймера (т. е., информация, возвращаемая getitimer()).

Если какое-то из полей в new_value.it_value не равно нулю, то таймер изначально включается как просроченный на указанное время. Если оба поля в new_value.it_value равны нулю, то таймер отключён.

Поле new_value.it_interval задаёт новый интервал таймера;если оба поля равны нулю, то таймер будет одноразовым.

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

## ОШИБКИ
EFAULT

Указатели new_value, old_value или curr_value являются некорректными.

EINVAL

Значение which не равно ITIMER_REAL, ITIMER_VIRTUAL или ITIMER_PROF; или (начиная с Linux 2.6.22) одно из полей структуры tv_usec, указанной в new_value, содержит значение вне диапазона от 0 до 999999.

## СООТВЕТСТВИЕ СТАНДАРТАМ
POSIX.1-2001, SVr4, 4.4BSD (впервые этот вызов появился в 4.2BSD). В POSIX.1-2008 вызовы getitimer() и setitimer() помечены как устаревшие, и вместо них рекомендуется использовать программный интерфейс таймеров POSIX (timer_gettime(2), timer_settime(2) и т.д.).

## ЗАМЕЧАНИЯ
Срок на таймерах никогда не заканчивается ранее указанного времени, но может (чуть-чуть) опоздать, что зависит от степени разрешения системного таймера и загрузки системы; смотрите time(7) (но смотрите ДЕФЕКТЫ далее). Если время таймера истекает во время работы процесса (всегда, если используется ITIMER_VIRTUAL), то сигнал после создания будет доставлен немедленно.

Потомок, созданный через fork(2), не наследует таймеры интервалов родителя. При вызове execve(2) таймеры интервалов сохраняются.

В POSIX.1 не определено взаимодействие между setitimer() и тремя интерфейсами: alarm(2), sleep(3) и usleep(3).

В стандартах ничего не говорится о значении вызова:

setitimer(which, NULL, &old_value);

В многих системах (Solaris, BSD и, возможно, другие) он считается эквивалентом:

getitimer(which, &old_value);

В Linux это эквивалентно вызову, в котором поля new_value равны 0, то есть таймер выключен. Не используйте это особенность Linux: это непереносимо и нецелесообразно.

## ДЕФЕКТЫ
Генерирование и доставка сигнала разделены, и только один экземпляр каждого сигнала, которые описаны выше, может ожидать передачи в процесс. При очень большой нагрузке, ожидание таймера ITIMER_REAL может завершиться раньше чем будет доставлен сигнал о предыдущем завершении. Второй сигнал об этом событии будет потерян.

В ядрах Linux до версии 2.6.16, значения таймеров указывались в мигах. Если запрашивалась установка таймера в значение, представление в мигах которого превышало MAX_SEC_IN_JIFFIES (определено в include/linux/jiffies.h), то значение таймера просто урезалось до этого максимального значения. На Linux/i386 (где, начиная с Linux 2.6.13, по умолчанию миг равен 0.004 секунды), это означало, что максимальное значение таймера приблизительно равнялось 99.42 дня. Начиная с Linux 2.6.16, в ядрах стали использовать другое внутреннее представление времени, и этот предел был снят.

В некоторых системах (включая i386), ядра Linux до версии 2.6.12 содержали дефект, который при определённых условиях приводил к преждевременному завершению за один миг (jiffy). Этот дефект исправлен в ядре 2.6.12.

В POSIX.1-2001 сказано, что setitimer() должен завершаться с ошибкой, если значение tv_usec лежит вне диапазона от 0 до 999999. Однако, в ядрах до версии 2.6.21 включительно, в Linux ошибка не выдаётся, а вместо этого значение таймера просто подгоняется под соответствующие секунды. Начиная с ядра 2.6.22, это несоответствие убрано: некорректное значение tv_usec приводит к ошибке EINVAL.

## СМОТРИТЕ ТАКЖЕ
gettimeofday(2), sigaction(2), signal(2), timer_create(2), timerfd_create(2), time(7)


getpagesize

title: getpagesize(2)

summary: определяет размер страницы памяти

text:
# getpagesize(2)

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

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

int getpagesize(void);

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

getpagesize():

Начиная с glibc 2.19:

```
_DEFAULT_SOURCE || ! (_POSIX_C_SOURCE >= 200112L)
```

В glibc с 2.12 по 2.19:

```
_BSD_SOURCE || ! (_POSIX_C_SOURCE >= 200112L)
```

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

## ОПИСАНИЕ
Вызов getpagesize() возвращает количество байтов в странице памяти, где «страница» представляет собой блок фиксированной длины, единица измерения при выделения памяти и файлового отображения, выполняемого с помощью mmap(2).

## СООТВЕТСТВИЕ СТАНДАРТАМ
SVr4, 4.4BSD, SUSv2. В SUSv2 вызов getpagesize() отмечен как УСТАРЕВШИЙ, и был удалён из POSIX.1-2001; в HP-UX такого вызова нет.

## ЗАМЕЧАНИЯ
В переносимых программах вместо getpagesize() следует использовать sysconf(_SC_PAGESIZE):

```
#include <unistd.h>
long sz = sysconf(_SC_PAGESIZE);
```

(большинство систем позволяют использовать _SC_PAGE_SIZE вместо _SC_PAGESIZE.)

В Linux системный вызов getpagesize() есть не на всех архитектурах. Если он есть, то он возвращает символ ядра PAGE_SIZE, чьё значение зависит от архитектуры и модели компьютера. Как правило, создаваемые двоичные файлы используются для всей архитектуры, а не для конкретной одной модели. Поэтому рекомендуется определять PAGE_SIZE не на стадии компиляции из файла заголовка, а при выполнении программы с помощью данной функции, по крайней мере на тех архитектурах (таких как sun), где зависимость от модели существует. В этом случае в библиотечные вызовы glibc 2.0 завершатся неудачно, так как её getpagesize() возвращает статически определённое значение и не использует системный вызов. В glibc 2.1 это исправлено.

## СМОТРИТЕ ТАКЖЕ
mmap(2), sysconf(3)


getpeername

title: getpeername(2)

summary: получает имя подключившегося сокета

text:
# getpeername(2)

## ИМЯ
getpeername - получает имя подключившегося сокета

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

int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

## ОПИСАНИЕ
getpeername() возвращает адрес машины, подключившейся к сокету sockfd, в буфер, указанный addr. В параметре addrlen должно быть указано, сколько места выделено, на которое указывает addr. По возвращении он содержит реальный размер памяти, занимаемый возвращаемым именем (в байтах). Имя обрезается, если буфер окажется слишком мал.

Возвращаемый адрес урежется, если предоставленный буфер окажется слишком маленьким; в этом случае в addrlen будет возвращено значение большее чем было в вызове.

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

## ОШИБКИ
EBADF

Аргумент sockfd не является допустимым файловым дескриптором.

EFAULT

Аргумент addr указывает на память в недопустимой части адресуемого пространства процесса.

EINVAL

Неправильное значение аргумента addrlen (например, отрицательное).

ENOBUFS

Недостаточно ресурсов в системе для выполнения операции.

ENOTCONN

Сокет не подключён.

ENOTSOCK

Файловый дескриптор sockfd указывает не на каталог.

## СООТВЕТСТВИЕ СТАНДАРТАМ
POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD, (getpeername() впервые появился в 4.2BSD).

## ЗАМЕЧАНИЯ
Описание типа socklen_t смотрите в accept(2).

Для потоковых сокетов после выполнения connect(2) любой сокет может вызвать getpeername() для получения адреса соседа (peer). С другой стороны, дейтаграмные сокеты не устанавливают соединения. Вызов connect(2) для дейтаграмного сокета просто задаст адрес соседа в исходящих дейтаграммах, посылаемых с помощью write(2) или recv(2). Вызывающий connect(2) может использовать getpeername() для получения адреса соседа., который был установлен у сокета ранее. Однако, сокет соседа не знает про это и вызов getpeername() для сокета соседа не вернёт полезной информации (если сосед также не вызвал connect(2)). Заметим, что получатель дейтаграммы может получить адрес отправителя, если использует recvfrom(2).

## СМОТРИТЕ ТАКЖЕ
accept(2), bind(2), getsockname(2), ip(7), socket(7), unix(7)


getpid

title: getpid(2)

summary: получение идентификатора процесса

text:
# getpid(2)

## ИМЯ
getpid, getppid - получение идентификатора процесса

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

\#include <unistd.h>

pid_t getpid(void);

pid_t getppid(void);

## ОПИСАНИЕ
Вызов getpid() возвращает идентификатор (PID) вызвавшего процесса (часто используется функциями, которые генерируют уникальные имена временных файлов).

Вызов getppid() возвращает идентификатор процесса, являющегося родительским по отношению к вызвавшему процессу. Результат равен идентификатору процесса, который создал этот процесс с помощью fork(), или идентификатору процесса, который заместил родителя (или init(1), или процесс «сборщик», определённый с помощью операции PR_SET_CHILD_SUBREAPER вызовом prctl(2)), если этот процесс уже завершён.

## ОШИБКИ
Функции всегда завершаются успешно.

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

## ЗАМЕЧАНИЯ
Если родитель вызывающего находит в другом пространстве имён PID (смотрите pid_namespaces(7)), то getppid() возвращает 0.

Со стороны ядра PID (одинаков у всех нитей в многонитевом процессе) иногда называют идентификатором группы нитей (TGID). Он отличается от идентификатора нити (TID), который является уникальным для каждой нити. Подробней смотрите в gettid(2) и описание флага CLONE_THREAD в clone(2).

### Отличия между библиотекой C и ядром
В версиях glibc с 2.3.4 по 2.24 включительно обёрточная функция glibc для getpid() кэширует PID, чтобы не делать дополнительных системных вызовов, когда процесс систематически вызывает getpid(). Обычно, это кэширование незаметно, но его корректность работы полагается на поддержку в обёрточных функциях для fork(2), vfork(2) и clone(2): если приложение не воспользуется обёртками glibc для этих системных вызовов, а вызовет из через syscall(2), то вызов getpid() в потомке вернёт неправильное значение (точнее, вернёт PID родительского процесса). Также, бывают случаи, когда getpid() может вернуть неверное значение даже при вызове clone(2) через обёрточную функцию glibc (описание одного из них смотрите в разделе ДЕФЕКТЫ в clone(2)). Кроме того, сложность кэширующего кода была источником нескольких дефектов в glibc многие годы.

Из-за вышеперечисленных проблем начиная с glibc версии 2.25 кэширование PID было удалено: вызов getpid() всегда вызывает реальный системный вызов, а не возвращает значение из кэша.

На Alpha вместо пары системных вызовов getpid() и getppid() предоставляется один getxpid(), который возвращает пару PID и родительский PID. Обёрточные функции glibc getpid() и getppid() скрывают это. Подробности об отображении регистров смотрите в syscall(2).

## СМОТРИТЕ ТАКЖЕ
clone(2), fork(2), gettid(2), kill(2), exec(3), mkstemp(3), tempnam(3), tmpfile(3), tmpnam(3), credentials(7), pid_namespaces(7)


getpriority

title: getpriority(2)

text:
# getpriority(2)

## ИМЯ
getpriority, setpriority - получить/установить приоритет планирования программы

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

\#include <sys/resource.h>

int getpriority(int which, id_t who);

int setpriority(int which, id_t who, int prio);

## ОПИСАНИЕ
С помощью вызова getpriority() можно получить приоритет планирования (scheduling priority) процесса, группы процессов или пользователя, которые заданы в аргументах which и who, а с помощью вызова setpriority() назначить его. Атрибут процесса этих системных вызовов тот же самый что атрибут (так называемое значение уступчивости «nice»), с которым работает вызов nice(2).

Значением which может быть одно из: PRIO_PROCESS, PRIO_PGRP или PRIO_USER, а значение who рассматривается относительно which (идентификатор процесса, если PRIO_PROCESS; группы процесса, если PRIO_PGRP; идентификатор пользователя, если PRIO_USER). Нулевое значение who означает (соответственно) вызывающий процесс, группу вызывающего процесса или реальный идентификатор пользователя вызывающего процесса.

Аргумент prio — это значение в диапазоне от -20 до 19 (смотрите ЗАМЕЧАНИЯ ниже), где -20 это наивысший приоритет, а 19 — наинизший. Попытка задать приоритет вне этого диапазона просто подгоняется под диапазон. По умолчанию приоритет равен 0; низкие значения дают процессу больший приоритет при планировании.

Вызов getpriority() возвращает наивысший приоритет (наименьшее числовое значение) из приоритетов всех указанных процессов. Вызов setpriority() устанавливает приоритеты всех указанных процессов в заданное значение.

Обычно, только привилегированный процесс может понижать значение уступчивости (т. е., повышать приоритет). Однако начиная с Linux 2.6.12 непривилегированный процесс может понизить значение уступчивости процесса назначения, у которого установлено подходящее мягкое ограничение RLIMIT_NICE; подробности смотрите в getrlimit(2).

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

При нормальном завершении работы setpriority() возвращает 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
EINVAL

Значение which не равно PRIO_PROCESS, PRIO_PGRP или PRIO_USER.

ESRCH

Не найдено процессов, которые заданы значениями which и who.

В дополнение к вышеуказанным ошибкам, setpriority() может завершиться неудачно:

EACCES

Вызывающий пытается понизить значение уступчивости (то есть повысить приоритет процесса), но он не имеет на это прав (в Linux: не имеет мандата CAP_SYS_NICE).

EPERM

Процесс был найден, но эффективному идентификатору пользователя этого процесса не соответствует заданный в вызове эффективный (или реальный) идентификатор вызывающего и у вызывающего нет прав (в Linux: не имеет мандата CAP_SYS_NICE). Смотрите ЗАМЕЧАНИЯ далее.

## СООТВЕТСТВИЕ СТАНДАРТАМ
POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD (эти интерфейсы впервые появились в 4.2BSD).

## ЗАМЕЧАНИЯ
Дополнительную информацию о значении уступчивости смотрите в sched(7).

Замечание: дополнительное свойство «autogroup» из Linux 2.6.38 означает, что значение уступчивости во многих случаях больше не работает как обычно. Подробней смотрите в sched(7).

Потомок, созданный с помощью fork(2), наследует значение nice родителя. При вызове execve(2) значение nice сохраняется.

Детали условия возникновения ошибки EPERM зависят от системы. Описание, приведённое выше, соответствует POSIX.1-2001, и, кажется, ему удовлетворяют все System V-подобные системы. Ядра Linux до версии 2.6.12 требуют, чтобы эффективный идентификатор пользователя вызывающего совпадал с реальным идентификатором пользователя процесса who (вместо его эффективного идентификатора пользователя). В Linux 2.6.12 и новее требуется, чтобы эффективный идентификатор пользователя вызывающего совпадал с реальным или эффективным идентификатором пользователя процесса who. Все системы BSD (SunOS 4.1.3, Ultrix 4.2, 4.3BSD, FreeBSD 4.3, OpenBSD-2.5, …) действуют также как Linux 2.6.12 и новее.

Включать <sys/time.h> в настоящее время не требуется, но это увеличивает переносимость (безусловно, в <sys/resource.h> определена структура rusage с полями типа struct timeval, которая определена в <sys/time.h>).

### Отличия между библиотекой C и ядром
Внутри ядра значения nice на самом деле представлены как диапазон (так как отрицательными числами задаются коды ошибок) и эти значения возвращаются системными вызовами setpriority() и getpriority(). Обёрточные функции glibc для этих системных вызовов преобразуют значение между пользовательским и ядерным диапазонами по формуле unice = 20 - knice (таким образом, ядерный диапазон 40..1 соответствует диапазону -20..19, видимый в пользовательском пространстве).

## ДЕФЕКТЫ
Согласно POSIX, значение nice — свойство процесса. Однако в текущей реализации Linux/NPTL нитей POSIX значение nice — атрибут нити: различные нити в одном процессе могут иметь разные значения nice. Переносимые приложения не должны полагаться на поведение Linux, которое может стать стандартом в будущем.

## СМОТРИТЕ ТАКЖЕ
nice(1), renice(1), fork(2), capabilities(7), sched(7)

Файл Documentation/scheduler/sched-nice-design.txt из дерева исходного кода ядра Linux (начиная с Linux 2.6.23)