packet

title: packet(7)

summary: пакетный интерфейс на уровне устройства

text:
# packet(7)

## ИМЯ
packet - пакетный интерфейс на уровне устройства

## ОБЗОР

```
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h> /* протоколы L2 */
```

```
packet_socket = socket(AF_PACKET, int socket_type, int protocol);
```

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

Значением socket_type может быть SOCK_RAW — для неструктурированных пакетов, содержащих заголовок уровня связи, или SOCK_DGRAM — для подготовленных (cooked) пакетов без заголовка уровня связи. Информация заголовка уровня связи имеет общий формат и предоставляется структурой sockaddr_ll. В protocol содержится номер протокола согласно IEEE 802.3 в сетевом порядке байт. Список допустимых протоколов можно найти в заголовочном файле <linux/if_ether.h>. Если значение протокола равно htons(ETH_P_ALL), то принимаются все протоколы. Все входящие пакеты с этим типом протокола будут переданы в пакетный сокет до их передачи протоколам, реализуемым в ядре.

Для создания пакетного сокета процесс должен иметь мандат CAP_NET_RAW в пользовательском пространстве имён, определяемом по его сетевому пространству имён.

Пакеты SOCK_RAW передаются в и из драйвера устройства без каких-либо изменений в данных пакета. При получении пакета, адрес по-прежнему анализируется и передаётся в стандартной адресной структуре sockaddr_ll. При отправке пакета, выделенный пользователем буфер должен содержать заголовок физического уровня. Этот пакет затем ставится без изменений в очередь сетевого драйвера интерфейса, определяемого адресом назначения. Некоторые драйверы устройств всегда добавляют другой заголовок. Пакеты SOCK_RAW похожи, но не совместимы с устаревшими AF_INET/SOCK_PACKET из Linux 2.0.

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

По умолчанию, все пакеты заданного типа протокола передаются в пакетный сокет. Для получения пакетов только из определённого интерфейса используйте bind(2), задав адрес в struct sockaddr_ll для привязки пакетного сокета к интерфейсу. Поля, используемые для привязывания: sll_family (должно быть равно AF_PACKET), sll_protocol и sll_ifindex.

Операция connect(2) не поддерживается для пакетных сокетов.

Если в recvmsg(2), recv(2) или recvfrom(2) передаётся флаг MSG_TRUNC, то возвращается реальная длина пакета в канале, даже если значение длиннее буфера.

### Типы адресов
Структура sockaddr_ll описывает независимый от устройства адрес на физическом уровне.

```
struct sockaddr_ll {

    unsigned short sll_family;   /* всегда равно AF_PACKET */

    unsigned short sll_protocol; /* протокол физического уровня */

    int            sll_ifindex;  /* номер интерфейса */

    unsigned short sll_hatype;   /* тип аппаратного ARP */

    unsigned char  sll_pkttype;  /* тип пакета */

    unsigned char  sll_halen;    /* длина адреса */

    unsigned char  sll_addr[8];  /* адрес на физическом уровне */
};
```

Поля этой структуры имеют следующее назначение:

- Поле sll_protocol содержит стандартные типы протокола ethernet в сетевом порядке байт; значения определены в заголовочном файле <linux/if_ether.h>. Это значение по умолчанию для протокола сокета.

- Поле sll_ifindex содержит индекс интерфейса (смотрите netdevice(7)); 0 означает любой интерфейс (допустимо только для привязывания). Поле sll_hatype содержит тип ARP; значения хранятся в заголовочном файле <linux/if_arp.h>.

- В поле sll_pkttype содержится тип пакета. Допустимые типы: PACKET_HOST — пакет предназначен локальному узлу, PACKET_BROADCAST — широковещательный пакет физического уровня, PACKET_MULTICAST — пакет, посланный на групповой (multicast) адрес физического уровня, PACKET_OTHERHOST — пакет предназначен не тому узлу, где он пойман драйвером устройства в неразборчивом режиме, PACKET_OUTGOING — пакет, поступивший от локального узла и завёрнутый обратно в пакетный сокет. Эти типы имеют смысл только для принятых пакетов.

- В полях sll_addr и sll_halen содержится адрес физического уровня (например, IEEE 802.3) и его длина. Конкретный смысл зависит от устройства.

Когда вы посылаете пакеты, достаточно указать sll_family, sll_addr, sll_halen, sll_ifindex и sll_protocol. Остальные поля должны равняться 0. Поля sll_hatype и sll_pkttype заполняются в получаемых пакетах для вашей информированности.

### Параметры сокета
Параметры пакетных сокетов настраиваются вызовом setsockopt(2) с уровнем SOL_PACKET.

PACKET_ADD_MEMBERSHIP

PACKET_DROP_MEMBERSHIP

Пакетные сокеты можно использовать для настройки неразборчивого режима и групповой рассылки на физическом уровне. Параметр PACKET_ADD_MEMBERSHIP добавляет привязку, PACKET_DROP_MEMBERSHIP отменяет её. Для обоих в качестве аргумента передаётся структура packet_mreq:

```
struct packet_mreq {

    int            mr_ifindex;    /* индекс интерфейса */

    unsigned short mr_type;       /* действие */

    unsigned short mr_alen;       /* длина адреса */

    unsigned char  mr_address[8]; /* адрес физ-кого уровня */
};

```

В mr_ifindex содержится индекс интерфейса, состояние которого нужно изменить. В поле mr_type указывается какое действие нужно выполнить. Значение PACKET_MR_PROMISC включает приём всех пакетов из общего носителя (часто называется «неразборчивый режим»), PACKET_MR_MULTICAST привязывает сокет к групповой рассылке физического уровня, задаваемой в mr_address и mr_alen, а PACKET_MR_ALLMULTI заставляет сокет принимать все пакеты групповых рассылок, поступающих на интерфейс.

Также, для тех же целей можно использовать обычные ioctl SIOCSIFFLAGS, SIOCADDMULTI, SIOCDELMULTI.

PACKET_AUXDATA (начиная с Linux 2.6.21)

Если включён этот двоичный параметр, то пакетный сокет передаёт структуру метаданных вместе с каждым пакетом в управляющем поле recvmsg(2). Структуру можно прочитать с помощью cmsg(3). Она определена как:

```
struct tpacket_auxdata {

    __u32 tp_status;

    __u32 tp_len;      /* длина пакета */

    __u32 tp_snaplen;  /* захваченная длина */

    __u16 tp_mac;

    __u16 tp_net;

    __u16 tp_vlan_tci;

    __u16 tp_padding;
};

```

PACKET_FANOUT (начиная с Linux 3.1)

Для масштабирования обработки на несколько нитей, пакетные сокеты можно объединять в разветвлённую группу (fanout group). В этом режиме каждый подходящий пакет ставится в очередь только одного сокета в группе. Сокет добавляется в разветвлённую группу вызовом setsockopt(2) с уровнем SOL_PACKET и параметром PACKET_FANOUT. Каждое сетевое пространство имён может включать до 65536 независимых групп. Сокет выбирает группу по закодированному ID в первых 16 битах целочисленного значения параметра. Первый пакетный сокет, подключаемый к группе неявно её создаёт. Для успешного подключения к существующей группе все дальнейшие пакетные сокеты должны иметь тот же протокол, настройки устройства, режим разветвления и флаги (смотрите далее). Пакетные сокеты могут покинуть группу только при закрытия сокета. Группа удаляется после закрытия последнего сокета.

Для разветвления поддерживается несколько алгоритмов распределения трафика по сокетам:

- Режим по умолчанию PACKET_FANOUT_HASH посылает пакеты из одного потока в один и тот же сокет для обеспечения упорядочивания по потоку. Для каждого пакета выбирается сокет, получаемый из хэша потока пакетов, взятого по модулю количества сокетов в группе, где хэш потока — это хэш адреса сетевого уровня и необязательных полей портов транспортного уровня.

- Режим балансировки нагрузки PACKET_FANOUT_LB реализует карусельный алгоритм.

- В режиме PACKET_FANOUT_CPU выбираются сокеты исходя из ЦП, на который поступил пакет.

- В режиме PACKET_FANOUT_ROLLOVER все данные обрабатываются одним сокетом, следующий задействуется, если текущий занят (backlogged).

- В режиме PACKET_FANOUT_RND сокет выбирается согласно генератору псевдослучайных чисел.

- В режиме PACKET_FANOUT_QM (доступен, начиная с Linux 3.14) сокет выбирается с помощью записанного queue_mapping из полученной skb.

Режимы разветвления могут учитывать дополнительные параметры. Фрагментация IP приводит к тому, что пакеты одного потока имеют разные хэши потоков. Если установлен флаг PACKET_FANOUT_FLAG_DEFRAG, то пакеты будут дефрагментироваться перед применением разветвления, что позволит сохранить порядок даже в этом случае. Параметры режима разветвления задаются во вторых 16 битах целочисленного значения параметра. Флаг PACKET_FANOUT_FLAG_ROLLOVER включает механизм перекатывания в качестве запасного: если первоначальный алгоритм разветвления выбрал занятый сокет, то пакет переходит на следующий доступный.

PACKET_LOSS (с PACKET_TX_RING)

Когда в кольце передачи обнаруживается некорректный пакет, то по умолчанию его состояние в tp_status сбрасывается в TP_STATUS_WRONG_FORMAT и происходит немедленная отмена передачи. Некорректный пакет блокирует как свою отправку, так и всех следующих пакетов в очереди. Ошибка в формате должна быть исправлена, соответствующий tp_status сброшен в значение TP_STATUS_SEND_REQUEST, а передача перезапущена с помощью send(2). Однако, если задан параметр PACKET_LOSS, то все некорректные пакеты будут пропускаться, их tp_status сбрасываться в TP_STATUS_AVAILABLE и процесс передачи продолжаться.

PACKET_RESERVE (с PACKET_RX_RING)

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

PACKET_RX_RING

Включает создание отображаемого в памяти кольцевого буфера асинхронного приёма пакетов. Пакетный сокет резервирует непрерывную область в адресном пространстве приложения, размечает её как массив пакетных слотов и последовательно копирует пакеты (не более tp_snaplen) в слоты. В начале каждого пакета помещается структура метаданных, похожая на tpacket_auxdata. В поле протокола кодируется смещение данных от начала заголовка метаданных. В tp_net хранится смещение сетевого уровня. Если тип пакетного сокета — SOCK_DGRAM, то это делается и для tp_mac. Если тип — SOCK_RAW, то в этом поле хранится смещение на кадр канального уровня. Пакетный сокет и приложение обмениваются началом и концом кольца через поле tp_status. Пакетному сокету принадлежат все слоты со значением tp_status равным TP_STATUS_KERNEL. После заполнения слота, изменяется состояние слота и права на него передаются приложению. При нормальной работе в новом значении tp_status, как минимум, установлен бит TP_STATUS_USER, что показывает, что принятый пакет был сохранён. Когда приложение заканчивает обработку пакета, оно передаёт права на слот обратно сокету посредством установки tp_status в значение TP_STATUS_KERNEL.

Для пакетных сокетов реализовано несколько вариантов пакетных колец. Информацию о реализации можно найти в файле Documentation/networking/packet_mmap.txt из дерева исходного кода ядра Linux.

PACKET_STATISTICS

Возвращает статистику по пакетному сокету в виде структуры

```
struct tpacket_stats {

    unsigned int tp_packets;  /* общее количество пакетов */

    unsigned int tp_drops;    /* кол-во отброшенных пакетов */
};

```

При получении статистики сбрасываются внутренние счётчики. Если используется вариант кольца TPACKET_V3, то статистика имеет другую структуру.

PACKET_TIMESTAMP (с PACKET_RX_RING; начиная с Linux 2.6.36)

В кольце приёма пакетов всегда сохраняется метка времени в заголовке метаданных. По умолчанию, это метка генерируется ПО при копировании пакета в кольцо. Данный целочисленный параметр задаёт тип метки времени. Кроме значения по умолчанию, поддерживается два аппаратных формата, описанных в файле Documentation/networking/timestamping.txt из дерева исходного кода ядра Linux.

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

Включает создание отображаемого в памяти кольцевого буфера передачи пакетов. Этот параметр подобен PACKET_RX_RING и имеет те же аргументы. Приложение записывает пакеты в слоты со значением tp_status равным TP_STATUS_AVAILABLE и планирует их для передачи делая значение tp_status равным TP_STATUS_SEND_REQUEST. Когда пакеты готовы к передаче, приложение вызывает send(2) или его вариант. Поля buf и len в этом вызове игнорируются. Если передаётся адрес с помощью sendto(2) или sendmsg(2), то он заменяет сокетное значение по умолчанию. При успешной передаче сокет сбрасывает значение tp_status в TP_STATUS_AVAILABLE. При ошибке передача немедленно прерывается, если не задан PACKET_LOSS.

PACKET_VERSION (с PACKET_RX_RING; начиная с Linux 2.6.27)

По умолчанию, PACKET_RX_RING создаёт кольцо приёма пакетов по варианту TPACKET_V1. Для создания другого варианта, задайте желаемый, указав целочисленное значение в этом параметре перед созданием кольца.

PACKET_QDISC_BYPASS (начиная с Linux 3.14)

По умолчанию, пакеты, посылаемые через пакетные сокеты, проходят через уровень ядра qdisc (управление трафиком), что правильно в подавляющем большинстве случаев. Для программно-аппаратных комплексов, использующих пакетные фильтры для затопления сети — например, для тестирования устройств под нагрузкой, подобно тому, как это делает pktgen — этот уровень можно не задействовать, установив целочисленной параметр в 1. Побочным эффектом будет отмена пакетной буферизации на уровне qdisc, что приведёт к увеличению отброшенных пакетов при занятости передающих очередей сетевого устройства; поэтому, пользуйтесь с осторожностью.

### Вызовы ioctl
Вызов SIOCGSTAMP можно использовать для получения метки времени последнего полученного пакета. Аргументом является struct timeval.

Также, для пакетных сокетов работают все стандартные ioctl, определённые в netdevice(7) и socket(7).

### Обработка ошибок
Пакетные сокеты не выполняют обработку ошибок, кроме ошибок, которые возникают при передаче пакета драйверу устройства. В них не заложен принцип ожидания ошибки.

## ОШИБКИ
EADDRNOTAVAIL

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

EFAULT

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

EINVAL

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

EMSGSIZE

Пакет больше, чем интерфейс MTU.

ENETDOWN

Интерфейс не поднят.

ENOBUFS

Недостаточно памяти для размещения пакета.

ENODEV

В адресе интерфейса указано неизвестное имя устройства или индекс интерфейса.

ENOENT

Пакет не принят.

ENOTCONN

Не передан адрес интерфейса.

ENXIO

В адресе интерфейса содержится некорректный индекс интерфейса.

EPERM

У пользователя недостаточно прав для выполнения этой операции.

Также, драйвером низкого уровня могут генерироваться другие ошибки.

## ВЕРСИИ
AF_PACKET появился в Linux 2.2. В ранних версиях Linux поддерживался только SOCK_PACKET.

## ЗАМЕЧАНИЯ
Для переносимых программ предлагается использовать AF_PACKET в pcap(3), хотя это покрывает не весь набор возможностей AF_PACKET.

Пакетные сокеты SOCK_DGRAM не пытаются создать или разобрать заголовок IEEE 802.2 LLC из кадров IEEE 802.3. Если для отправки в качестве протокола указан ETH_P_802_3, то ядро создаёт кадр 802.3 и заполняет поле длины; пользователь передаёт заголовок LLC в пакете уже полностью заполненным. Входящие пакеты 802.3 не уплотняются по полям протокола DSAP/SSAP; вместо этого они передаются пользователю как протокол ETH_P_802_2 с начальным заголовком LLC. То есть невозможно выполнить привязку к ETH_P_802_3; вместо этого выполняйте привязку к ETH_P_802_2 и выполняйте протокольное уплотнение самостоятельно. По умолчанию, отправка происходит в стандартной упаковке Ethernet DIX с заполненным полем протокола.

Пакетные сокеты недоступны (not subject) во входной и выходной цепочках межсетевого экрана.

### Совместимость
В Linux 2.0 единственным способом получить пакетный сокет является вызов:

socket(AF_INET, SOCK_PACKET, протокол)

Он всё ещё поддерживается, но устарел и настоятельно не рекомендуется. Основным отличием между методами — для указания интерфейса через SOCK_PACKET используется старая struct sockaddr_pkt, которая не предоставляет независимого физического уровня.

```
struct sockaddr_pkt {

    unsigned short spkt_family;

    unsigned char  spkt_device[14];

    unsigned short spkt_protocol;
};
```

В spkt_family содержится тип устройства, в spkt_protocol — тип протокола IEEE 802.3, определённый в <sys/if_ether.h>, а в spkt_device — имя устройства в виде строки с null в конце, например, eth0.

Эта структура устарела и не должна использоваться в новом коде.

## ДЕФЕКТЫ
Способ обработки IEEE 802.2/803.3 LLC не считается за дефектный.

Не описаны сокетные фильтры.

Расширение MSG_TRUNC recvmsg(2) является неудачным решением и должно быть заменено на управляющее сообщение. Пока нет способа получить первоначальный адрес назначения пакетов через SOCK_DGRAM.

## СМОТРИТЕ ТАКЖЕ
socket(2), pcap(3), capabilities(7), ip(7), raw(7), socket(7)

В RFC 894 описана упаковка стандартного IP Ethernet. В RFC 1700 описана упаковка IP IEEE 802.3.

Заголовочный файл <linux/if_ether.h> содержит протоколы физического уровня.

Дерево исходного кода ядра Linux. В /Documentation/networking/filter.txt описано как к пакетным сокетам применять Berkeley Packet Filters. В /tools/testing/selftests/net/psock_tpacket.c содержится пример исходного кода для всех доступных версий PACKET_RX_RING и PACKET_TX_RING.


package: man-pages-ru

title: path_resolution(7)

summary: как путь преобразуется в файл

text:
# path_resolution(7)

## ИМЯ
path_resolution - как путь преобразуется в файл

## ОПИСАНИЕ
У некоторых системных вызовов UNIX/Linux есть параметр для указания одного или нескольких имён файлов. Имя файла (или путь) преобразуется (resolved) следующим образом.

### Шаг 1: запуск процесса преобразования
Если путь начинается с символа «/», то начальным каталогом поиска назначается корневой каталог вызывающего процесса (процесс наследует свой корневой каталог от родителя. Обычно, это корневой каталог файловой иерархии. Процесс может получить другой корневой каталог, используя системный вызов chroot(2). Процесс может получить полностью закрытое пространство имён монтирования когда он сам или один из его предков был запущен системным вызовом clone(2) с флагом CLONE_NEWNS). Так обрабатывается часть пути «/».

Если путь не начинается с символа «/», то начальным каталогом поиска процесса преобразование выбирается текущий рабочий каталог процесса (также наследуемый от родителя; может быть системным вызовом chdir(2)).

Пути, начинающиеся с символа «/», называются абсолютными путями. Пути, не начинающиеся с символа «/», называются относительными путями.

### Шаг 2: обход пути
Назначаем текущим каталогом поиска начальный каталог поиска. Теперь для каждого не конечного компонента пути (подстрока, разделённая символами «/») будет производиться поиск в текущем каталоге поиска.

Если у процесса нет права поиска в текущем каталоге просмотра, будет возвращена ошибка EACCES («Доступ запрещён»).

Если компонент не найдет, будет возвращена ошибка ENOENT («Нет такого файла или каталога»).

Если компонент найден, но не является ни каталогом, ни символической ссылкой, будет возвращена ошибка ENOTDIR («Не является каталогом»).

Если компонент найден и является каталогом, значением текущего каталога поиска устанавливается этот каталог, после чего осуществляется переход к следующему компоненту.

Если компонент найден и это символическая ссылка (symlink), то сначала мы разрешаем эту символическую ссылку (от текущего каталога, как начального пути поиска). При ошибках, возвращаем ошибку. Если результат не каталог, то возвращается ошибка ENOTDIR. Если разрешение символической ссылки удалось и получен каталог, то мы назначаем этот каталог текущим каталогом поиска и переходим к следующему компоненту. Заметим, что процесс разрешения здесь может вызвать рекурсию, если компонент префикса («dirname») пути содержит имя символической ссылки, которая разрешается в каталог (где префикс компонента этого каталога может содержать символическую ссылку и т .д.). Для защиты ядра от переполнения стека, а также от отказа в обслуживании, есть ограничение на максимальную глубину рекурсии и на максимальное количество переходов по символическим ссылкам. При превышении возвращается ошибка ELOOP («Слишком много уровней символических ссылок»).

В текущей реализации Linux максимальное количество допустимых переходов по символическим ссылкам при преобразовании пути равно 40. В ядрах до версии 2.6.18 ограничение глубины рекурсии было равно 5. Начиная с Linux 2.6.18, это ограничение увеличилось до 8. В Linux 4.2 код ядра разрешения пути был переработан и возникновение рекурсии больше не происходит, поэтому осталось только ограничение на 40 разрешений для всего пути.

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

### . и ..
По соглашению, в каждом каталоге есть записи «.» и «..», которые ссылаются на сам каталог и на его родительских каталог, соответственно.

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

Невозможно перейти за пределы корня: путь «/..» равен «/».

### Точки монтирования
После команды «mount устройство путь» путь указывает на корень иерархии файловой системы устройства, и больше не указывает на то, что было раньше.

Можно выйти за пределы смонтированной файловой системы: «путь/..» указывает на родительский каталог «пути», лежащий вне иерархии файловой системы устройства.

### Конечные символы косой черты
Если путь заканчивается на «/», то это приводит к обработке предыдущего компонента согласно шагу 2: он существует и преобразуется в каталог. В противном случае конечный «/» будет проигнорирован (или, что тоже самое, путь с конечной косой чертой «/» будет равен пути, полученному добавлением к его концу «.»).

### Символьная ссылка в конце
Если последний компонент пути является символической ссылкой, то это зависит от системного вызова, будет ли файл указывать на саму символическую ссылку или на её содержимое. Например, системный вызов lstat(2) будет работать с символической ссылкой, а stat(2) работает с файлом, на который указывает символическая ссылка.

### Ограничение длины
Существует максимально допустимая длина пути. Если путь (или какой-нибудь промежуточный путь, полученный при разрешении символических ссылок) очень длинный, то возвращается ENAMETOOLONG («Имя файла очень длинное»).

### Пустой путь
В оригинальном UNIX, пустой путь считался текущим каталогом. В наши дни в POSIX указано, что пустой путь не должен быть преобразован без ошибки. В Linux в этом случае возвращается ENOENT.

### Права доступа
Биты прав файла делятся на три группы по три бита; смотрите chmod(1) и stat(2). Первая группа используется тогда, когда эффективный идентификатор пользователя вызывающего процесса равен идентификатору владельца файла. Вторая группа используется, если идентификатор группы файла равен эффективному идентификатору группы вызывающего процесса или одному из дополнительных групп вызывающего процесса (установленных setgroups(2)). В остальных случаях используется третья группа.

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

Для проверки доступа в Linux используется fsuid вместо эффективного идентификатора пользователя. Обычно, fsuid равен эффективному идентификатору пользователя, fsuid может быть изменён системным вызовом setfsuid(2).

(Здесь «fsuid» сокращение от «пользовательский идентификатор в файловой системе, filesystem user ID». Это требовалось для реализации сервера NFS в пользовательском пространстве во времена, когда процессы могли посылать сигнал процессу с тем же эффективным идентификатором пользователя. Сейчас это устарело. Никто не должен использовать setfsuid(2).)

Схожим образом в Linux используется fsgid ("filesystem group ID") вместо идентификатора эффективной группы. Смотрите setfsgid(2).

### Пропуск проверки прав доступа: суперпользователь и мандаты
В традиционных системах UNIX суперпользователю (root, идентификатор пользователя 0) доступно всё и при доступе к файлам никаких проверок ограничений не производится.

В Linux права суперпользователя делятся мандатами (смотрите capabilities(7)). Два мандата относятся к проверка доступа к файлам: CAP_DAC_OVERRIDE и CAP_DAC_READ_SEARCH (процесс имеет эти мандаты, если его fsuid равен 0).

Мандат CAP_DAC_OVERRIDE заменяет всех проверки прав, но позволяет право выполнения только, когда установлен хотя бы один из трёх битов выполнения файла.

Мандат CAP_DAC_READ_SEARCH разрешает чтение и поиск в по каталогу, а также чтение обычных файлов.

## СМОТРИТЕ ТАКЖЕ
readlink(2), capabilities(7), credentials(7), symlink(7)


persistent-keyring

title: persistent-keyring(7)

text:
# persistent-keyring(7)

## ИМЯ
persistent-keyring - пользовательская постоянная связка ключей

## ОПИСАНИЕ
Постоянная связка ключей — это связка, используемая для привязки от имени пользователя. Для каждого UID ядро создаёт отдельную постоянную связку ключей, которая используется всеми нитями, принадлежащими этому UID. Постоянная связка ключей имеет имя (описание) в виде _persistent.<UID>, <UID> — ID пользователя соответствующего пользователя.

Прямой доступ к постоянной связке ключей невозможен, даже процессам с подходящим UID. Вместо этого сначала она должна быть прицеплена к одной из связок ключей процесса, до этого связка ключей может получить доступ к постоянной связке ключей согласно правам своего владельца. Эта связь создаётся с помощью функции keyctl_get_persistent(3).

Если постоянная связка ключей не существует на момент вызова операции keyctl_get_persistent(3), то она автоматически создаётся.

Каждый раз при выполнении операции keyctl_get_persistent(3) срок действия постоянного ключа сбрасывается в значение:

/proc/sys/kernel/keys/persistent_keyring_expiry

По истечению срока действия постоянная связка ключей удаляется и все ссылки на неё затем удаляются сборщиком мусора. После этого ключ будет пересоздан при следующем вызове keyctl_get_persistent(3).

В постоянной связке ключей напрямую невозможно искать с помощью request_key(2); в ней можно искать только, если она прицеплена к одной из связок ключей, по которой выполняется request_key(2).

Постоянная связка ключей не зависит от clone(2), fork(2), vfork(2), execve(2) и _exit(2). Она существует до истечения срока действия таймера, после чего удаляется сборщиком мусора. Это позволяет связке ключей хранить ключи дольше жизни ядерной записи соответствующего UID (удаление которой приводит к уничтожению user-keyring(7) и user-session-keyring(7)). Таким образом, постоянную связку ключей можно использовать для хранения токенов аутентификации для процессов, которые выполняются без взаимодействия с пользователем, например программы, выполняемые cron(8).

Постоянная связка ключей используется для хранения объектов, для UID, которые сами имеют ограниченный срок жизни (например, токены kerberos). Если такие токены больше не используются (т. е., связка ключей недоступна), то срок действия постоянной связки ключей позволяет автоматически удалять соответствующие ей объекты.

### Специальные операции
Библиотека keyutils для работы с постоянными связками ключей предоставляет функцию keyctl_get_persistent(3) (эта функция является интерфейсом к операции keyctl(2) KEYCTL_GET_PERSISTENT). Данная операция позволяет вызывающей нити получить постоянную связку ключей, соответствующую её UID или, если нить имеет мандат CAP_SETUID, то постоянная связка ключей соответствует какому-то другому UID в этом же пространстве имён пользователя.

## ЗАМЕЧАНИЯ
Каждое пространство имён пользователя имеет свою связку ключей с именем .persistent_register, в которой содержатся ссылки на все постоянные ключи в этом пространстве имён (связку ключей .persistent_register можно увидеть при чтении в пространстве имён содержимого файла /proc/keys для UID 0). Операция keyctl_get_persistent(3) ищет ключ с именем в виде _persistent.<UID> в этой связке ключей, создаёт ключ, если он не существует и прицепляет его в связку ключей.

## СМОТРИТЕ ТАКЖЕ
keyctl(1), keyctl(3), keyctl_get_persistent(3), keyrings(7), process-keyring(7), session-keyring(7), thread-keyring(7), user-keyring(7), user-session-keyring(7)


title: pid_namespaces(7)

summary: обзор пространств имён Linux PID

text:
# pid_namespaces(7)

## ИМЯ
pid_namespaces - обзор пространств имён Linux PID

## ОПИСАНИЕ
Обзор пространств имён смотрите в namespaces(7).

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

Идентификаторы в новом пространстве имён PID начинаются с 1 как в автономной системе, и вызовы fork(2), vfork(2) или clone(2) будут создавать процессы с уникальными идентификаторами в пределах пространства имён.

Для использования пространств имён PID требуется, чтобы ядро было собрано с параметром CONFIG_PID_NS.

### Пространство имён начального процесса
Первый процесс, созданный в новом пространстве имён (т. е., процесс, созданный вызовом clone(2) с флагом CLONE_NEWPID или первый потомок, созданный процессом после вызова unshare(2) с флагом CLONE_NEWPID) имеет PID 1, и это «начальный» (init) процесс пространства имён (смотрите init(1)). Этот процесс становится родителем всех дочерних процессов, которые осиротели из-за завершения родителей, находящихся внутри этого пространства имён PID (дополнительную информацию смотрите ниже).

Если процесс «init» пространства имён PID завершает работу, то ядро завершает работу всех процессов в пространстве имён с помощью сигнала SIGKILL. Такое поведение показывает, что процесс «init» необходим для корректной работы пространства имён PID. В этом случае последующий вызов fork(2) в этом пространство имён PID завершается ошибкой ENOMEM; невозможно создать новый процесс в пространстве имён PID, в котором не работает процесс «init». Такое может произойти, например, когда процесс использует открытый файловый дескриптор файла /proc/[pid]/ns/pid, соответствующий процессу, который был в пространстве имён setns(2), в этом пространстве имён после того, как процесс «init» завершился. Другой возможный сценарий может произойти после вызова unshare(2): если первый потомок после этого созданный fork(2) завершится, то последующие вызовы fork(2) завершаются ошибкой ENOMEM.

Члены пространства имён PID могут посылать процессу «init» только сигналы, для которых процесс «init» установил обработчики. Это ограничение применяется даже к привилегированным процессам, и не позволяет другим членам пространства имён PID нечаянно убить процесс «init».

Также, процесс в родительском пространстве имён может (пройдя обычные проверки прав, описанные в kill(2)) послать сигнал процессу «init» дочернего пространства имён PID только, если процесс «init» задал обработчики для этого сигнала (внутри обработчика si_pid в siginfo_t, описанное в sigaction(2) будет равно нулю). Для сигналов SIGKILL и SIGSTOP сделано исключение: эти сигналы принудительно доставляются при отправке из родительского пространства имён PID. Ни один из них не может быть пойман процессом «init», и в результате будут выполнены обычные действия, связанные с этими сигналами (завершение и останов процесса, соответственно).

Начиная с Linux 3.4, системный вызов reboot(2) посылает сигнал в пространство имён процесса «init». Подробности смотрите в reboot(2).

### Вложенные пространства имён PID
Пространства имён PID могут быть вложенными: каждое пространство имён PID имеет родителя, за исключением начального («корневого») пространства имён PID. Родитель пространства имён PID — это пространство имён PID процесса, который был создан в пространстве имён с помощью clone(2) или unshare(2). Таким образом пространства имён PID образуют дерево со всеми пространствами имён по которому, в конечном счёте, можно проследить их родословную до корневого пространства имён. Начиная с Linux 3.7, ядро ограничивает глубину максимальной вложенности пространств имён PID значением 32.

Процесс видим другим процессам в своём пространстве имён PID, и процессам в каждом прямом родительском пространстве имён PID вплоть до корневого пространства имён PID. В этом контексте «видимость» означает, что процесс может быть целью операции другого процесса в системных вызовах, который указывает идентификатор процесса. И наоборот, процессы в дочернем пространстве имён PID не видят процессы в родительском и более удалённых родительских пространствах имён. Более кратко: процесс может видеть (например, посылать сигналы с помощью kill(2), назначать значения уступчивости с помощью setpriority(2) и т. п.) только процессы из своего пространства имён PID и в потомках этого пространства имён.

Процесс имеет идентификатор в каждом слое иерархии пространства имён PID, в котором он виден, и двигаясь назад, в каждом прямом предке пространства имён вплоть до корневого пространства имён PID. Системные вызовы, работающие с идентификатором процесса, всегда используют идентификатор процесса, который видим в пространстве имён PID вызывающего. Вызов getpid(2) всегда возвращает PID, связанный с пространством имён, в котором был создан процесс.

Некоторые процессы в пространстве имён PID могут иметь родителей, которые находятся вне пространства имён. Например, родитель начального процесса в пространстве имён (т. е., процесс init(1) с PID 1) неизбежно находится в другом пространстве имён. Аналогичным образом, прямые потомки процесса, который использует setns(2) для объединения потомков в пространство имён PID, находятся в другом пространстве имён PID относительно вызывающего setns(2). При вызове getppid(2) для таких процессов возвращает 0.

Хотя процессы могут свободно перемещаться вниз в дочерние пространства имён PID (например, с помощью setns(2) с файловым дескриптором пространства имён PID), они не могут перемещаться в обратном направлении. То есть процессы не могут входить в пространства имён предка (родителя, прародителя и т .п.). Изменение пространств имён PID — это односторонняя операция.

Операцию NS_GET_PARENT ioctl(2) можно использовать для обнаружения родительской связи между пространствами имён PID; смотрите ioctl_ns(2).

### Семантика setns(2) и unshare(2)
Последовательно выполняемые вызовы setns(2) с файловым дескриптором пространства имён PID и вызов unshare(2) с флагом CLONE_NEWPID помещают потомков в другое пространство имён PID, отличное от пространства вызывающего (начиная с Linux 4.12 данное пространство имён PID показывается через файл /proc/[pid]/ns/pid_for_children как описано в namespaces(7)). Однако, эти вызовы не изменяют пространство имён PID вызывающего процесса, так как это позволило бы изменять PID вызывающего (сообщаемые getpid()), что сломало бы многие приложения и библиотеки.

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

Процесс может вызвать unshare(2) с флагом CLONE_NEWPID только один раз. После выполнения этой операции его символическая ссылка /proc/PID/ns/pid_for_children станет пустой, пока пространстве имён не будет создать первый потомок.

### Усыновление осиротевших потомков
Когда дочерний процесс становится сиротой, его родителем становится «начальный» процесс в пространстве имён PID его родителя (если один из ближайших родственных процессов родителя не вызывал команду prctl(2) PR_SET_CHILD_SUBREAPER для назначения себя сборщиком собирателем дочерних процессов). Заметим, что благодаря семантике setns(2) и unshare(2), описанной выше, это может быть процесс «init» в пространстве имён PID, являющийся родителем пространства имён PID потомка, а не процесс «init» пространства имён PID самого потомка.

### Совместимость CLONE_NEWPID с другими флагами CLONE_*
В текущих версиях Linux CLONE_NEWPID нельзя объединять вместе с CLONE_THREAD. Для нитей требуется находиться в том же пространстве имён PID, чтобы нити процесса могли посылать сигналы друг другу. Также требуется видеть все нити процессов в файловой системе proc(5). Также, если две нити находятся в разных пространствах имён PID, то ID процесса, посылающего сигнал, невозможно достоверно закодировать при посылке (смотрите описание типа siginfo_t в sigaction(2)). Так как вычисление выполняется когда сигнал попадает в очередь сигналов, общая для процессов из нескольких пространств имён PID, очередь сигналов не позволяет этого.

В ранних версиях Linux значение CLONE_NEWPID также запрещалось (возвращалась ошибка EINVAL) объединять с CLONE_SIGHAND (до Linux 4.3), а также с CLONE_VM (до Linux 3.12). Изменения, снявшие эти ограничения, были также перенесены в более ранние стабильные ядра.

### /proc и PID пространств имен
В файловой системе /proc отображаются (в каталогах /proc/[pid]) только процессы, видимые в пространстве имён PID процесса, который выполнил монтирование, даже если файловая система /proc видима из процессов другого пространства имён.

После создания нового пространства имён PID у потомка полезно изменить его корневой каталог и смонтировать новый экземпляр procfs в /proc для того, чтобы корректно работали инструменты типа ps(1). Если одновременно создаётся новое пространство имён монтирования, добавлением флага CLONE_NEWNS в аргумент flags вызова clone(2) или unshare(2), то необязательно изменять корневой каталог: новый экземпляр procfs можно смонтировать непосредственно в /proc.

Команда оболочки для монтирования /proc:

```
$ mount -t proc proc /proc
```

Вызов readlink(2) с путём /proc/self выдаёт идентификатор процесса вызывающего из пространства имён PID, откуда смонтирован procfs (т. е., из пространства имён PID процесса, который смонтировал procfs). Это может быть полезно при самоанализе, когда процесс хочет узнать свой PID в других пространствах имён.

### Файлы в /proc
/proc/sys/kernel/ns_last_pid (начиная с Linux 3.3)

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

Этот файл доступен на запись процессу с мандатом CAP_SYS_ADMIN внутри своего пространства имён пользователя. Это делает возможным задать PID, который выделяется следующему процессу, создаваемому внутри этого пространства имён PID.

### Разное
Когда идентификатор процесса передаётся через доменный сокет UNIX в процесс в другом пространстве имён PID (смотрите описание SCM_CREDENTIALS в unix(7)), то он транслируется в соответствующее значения PID из пространства имён PID принимающего процесса.

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

## ПРИМЕР
См. user_namespaces(7).

## СМОТРИТЕ ТАКЖЕ
clone(2), reboot(2), setns(2), unshare(2), proc(5), capabilities(7), credentials(7), mount_namespaces(7), namespaces(7), user_namespaces(7), switch_root(8)


pipe

title: pipe(7)

summary: обзор каналов и FIFO

text:
# pipe(7)

## ИМЯ
pipe - обзор каналов и FIFO

## ОПИСАНИЕ
Каналы и FIFO (также называемые именованными каналами) предоставляют двунаправленный канал обмена между процессами. У канала имеется конец для чтения (read end) и конец для записи (write end). Данные, записанные в конец для записи, можно прочитать из конца для чтения.

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

У FIFO (сокращение от First In First Out, первым вошёл, первым вышел) имеется имя в файловой системе (создаётся с помощью mkfifo(3)), и такой канал открывается с помощью open(2). Любой процесс может открыть FIFO, если это ему разрешено правами на файл. Конец для чтения открывается при указании флага O_RDONLY; конец для записи открывается при указании флага O_WRONLY. Подробней смотрите fifo(7). Замечание: хотя у FIFO есть путь в файловой системе, при вводе-выводе из FIFO не используются операции с нижележащим устройством (если оно есть).

### Ввод-вывод из каналов и FIFO
Каналы и FIFO отличаются только способом создания и открытия. После выполнения этих задач, ввод-вывод из каналов и FIFO имеет одинаковую семантику.

Если процесс пытается выполнить чтение из пустого канала, то read(2) заблокирует выполнение в ожидании данных. Если процесс пытается выполнить запись в заполненный канал (смотрите далее), то write(2) заблокирует выполнение до тех пор, пока из канала не будут прочитаны данные, чтобы можно было записать ожидающие. Возможен неблокируемый ввод-вывод с помощью вызова fcntl(2) с операцией F_SETFL, включающей флаг O_NONBLOCK в состоянии открытого файла.

Канал обмена, предоставляемый каналом, является потоком байт: какие-либо границы сообщений отсутствуют.

Если все файловые дескрипторы, указывающие на конец канала для записи, были закрыты, то попытка выполнить read(2) из канала возвратит конец файла (read(2) вернёт 0). Если все файловые дескрипторы, указывающие на конец канала для чтения, были закрыты, то write(2) завершится сигналом SIGPIPE, который будет послан вызывающему процессу. Если вызывающий процесс игнорирует этот сигнал, то write(2) завершится ошибкой EPIPE. Приложение, использующее pipe(2) и fork(2), должно использовать правильные вызовы close(2) для закрытия ненужных копий файловых дескрипторов; это обеспечит появления конца файла и доставку SIGPIPE/EPIPE в подходящий момент.

Для канала невозможно вызвать lseek(2).

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

В Linux до версии 2.6.11, ёмкость канала была равна размеру системной страницы (4096 байт на i386). Начиная с Linux 2.6.11, ёмкость канала равна 16 страницам (т. е., 65536 байтам в системе с размером страницы в 4096 байта). Начиная с Linux 2.6.35, ёмкость канала по умолчанию равна 16 страницам, но это значение можно прочитать и изменить с помощью вызова fcntl(2) с операциями F_GETPIPE_SZ и F_SETPIPE_SZ. Подробности смотрите в fcntl(2).

Следующая операция ioctl(2), которая может быть применена к файловому дескриптору, указывающему на любой конец канала, помещает количество непрочитанных байт канала в буфер int, задаваемый последним аргументом вызова:

ioctl(fd, FIONREAD, &nbytes);

Операция FIONREAD отсутствует в стандартах, но имеется во многих реализациях.

### Файлы в /proc
В Linux управление количеством памяти каналов осуществляется через следующие файлы:

/proc/sys/fs/pipe-max-pages (только в Linux 2.6.34)

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

Значение по умолчанию этого ограничения равно 16 кратному размеру ёмкости канала по умолчанию (смотрите выше); нижнее ограничение равно 2м страницам.

Данный интерфейс удалён в Linux 2.6.35; его заменяет /proc/sys/fs/pipe-max-size.

/proc/sys/fs/pipe-max-size (начиная с Linux 2.6.35)

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

Значение по умолчанию равно 1048576 (1 МиБ). Минимальное значение равно размеру системной страницы. При попытке задать меньшее значение вызов write(2) завершится ошибкой EINVAL.

Начиная с Linux 4.9 значение в данном файле также служит верхним пределом ёмкости по умолчанию для новых каналов или открываемых FIFO.

/proc/sys/fs/pipe-user-pages-hard (начиная с Linux 4.5)

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

Если значение этого ограничения равно нулю (по умолчанию), то жёсткое ограничение не применяется.

/proc/sys/fs/pipe-user-pages-soft (начиная с Linux 4.5)

Мягкое ограничение на общий размер (в страницах) всех каналов создаваемых или изменяемых одним непривилегированным пользователем (т. е., без мандата CAP_SYS_RESOURCE или CAP_SYS_ADMIN). Пока общее количество страниц, выделенных под буферы каналов для этого пользователя, равно этому ограничению, отдельные каналы, создаваемые пользователем, будут ограничены одной страницей, а попытки увеличить ёмкость канала будут отклоняться.

Если значение этого ограничения равно нулю, то мягкое ограничение не применяется. По умолчанию значение в этом файле равно 16384, что позволяет создать до 1024 каналов с ёмкостью по умолчанию.

До Linux 4.9 имелись дефекты, влияющие на обработку ограничений pipe-user-pages-soft и pipe-user-pages-hard; смотрите ДЕФЕКТЫ.

### PIPE_BUF
В POSIX.1 указано, что операция write(2) для записи меньше чем PIPE_BUF байт должна быть атомарна: выходные данные записываются в канал как непрерывная последовательность. Запись более PIPE_BUF байт может быть не атомарна: ядро может чередовать данные с данными, записываемыми другими процессами. В POSIX.1 требуется, чтобы значение PIPE_BUF было не менее 512 байт (в Linux, PIPE_BUF равно 4096 байт). Точная семантика зависит от вида блокированности файлового дескриптора (O_NONBLOCK), есть ли несколько писателей в канала и от n, количества записываемых байт:

O_NONBLOCK сброшен, n <= PIPE_BUF

Все n байт записываются атомарно; write(2) может заблокироваться, если нет места для немедленной записи n байт

O_NONBLOCK установлен, n <= PIPE_BUF

Если есть место для записи n байт в канал, то write(2) немедленно завершается без ошибки, записывая все n байт; в противном случае write(2) завершается с ошибкой, а errno присваивается значение EAGAIN.

O_NONBLOCK сброшен, n > PIPE_BUF

Запись не атомарна: данные, переданные во write(2), могут чередоваться с write(2) из других процессов; write(2) блокируется до тех пор, пока не будут записаны n байт.

O_NONBLOCK установлен, n > PIPE_BUF

Если канала переполнен, то write(2) завершается с ошибкой, а errno присваивается значение EAGAIN. В противном случае, может быть записано от 1 до n байт (т. е., может произойти «частичная запись»; вызывающий должен проверить возвращаемое значение write(2), чтобы узнать сколько байт действительно записано), и эти байты могут чередоваться с данными, записанными другими процессами.

### Флаги состояния открытого файла
К каналу и FIFO из флагов состояния открытого файла применимы только O_NONBLOCK и O_ASYNC.

Установка флага O_ASYNC для чтения от конца канала проводит к генерации сигнала (по умолчанию SIGIO) при появлении новых данных в канале. Получатель сигнала должен быть указан с помощью команды F_SETOWN вызовом fcntl(2). В Linux O_ASYNC поддерживается для каналов и FIFO только начиная с ядра версии 2.6.

### Замечания о переносимости
В некоторых системах (но не в Linux), каналы являются двунаправленными: данные можно передавать в обоих направлениях между концами канала. Согласно POSIX.1 требуются только однонаправленные каналы. Переносимые приложения не должны зависеть от семантики двунаправленных каналов.

### ДЕФЕКТЫ
До Linux 4.9 имелись дефекты, влияющие на обработку ограничений pipe-user-pages-soft и pipe-user-pages-hard при операции fcntl(2) F_SETPIPE_SZ по изменению ёмкости канала:

(1)

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

Начиная с Linux 4.9 при проверке ограничения добавляется память, требуемая под ёмкость нового канала.

(2)

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

Начиная с Linux 4.9 проверки ограничений выполняются только когда ёмкость канала увеличивается; непривилегированный пользователь всегда может уменьшить ёмкость канала.

(3)

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

(а)

Выполнялась проверка не превышает ли пользователь ограничение.

(б)

Выделялся буфер под новый канал.

(в)

Учитывалось новое выделение в ограничениях.

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

Начиная с Linux 4.9, шаг учёта выполняется до выделения и операция завершается с ошибкой, если бы было превышение ограничения.

До Linux 4.9, дефекты подобные (1) и (3), также могли происходить, когда ядро выделяет память под буферы нового канала; то есть, когда вызывается pipe(2) и когда открывается ранее не открытый FIFO.

## СМОТРИТЕ ТАКЖЕ
mkfifo(1), dup(2), fcntl(2), open(2), pipe(2), poll(2), select(2), socketpair(2), splice(2), stat(2), tee(2), vmsplice(2), mkfifo(3), epoll(7), fifo(7)


pkeys

title: pkeys(7)

summary: обзор ключей защиты памяти

text:
# pkeys(7)

## ИМЯ
pkeys - обзор ключей защиты памяти

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

Чтобы использовать pkeys, ПО сначала должно «пометить» (tag) страницу в страничных таблицах значением pkey. После размещения этой метки для удаления прав на запись или весь доступ к помеченной странице приложению нужно изменить только содержимое регистра.

Ключи защиты вместе с существующими правами PROT_READ/ PROT_WRITE/ PROT_EXEC передаются в системные вызовы, такие как mprotect(2) и mmap(2), но всегда считаются как дополнительное ограничение к существующим традиционным механизмам прав доступа.

Если процесс осуществляет доступ, нарушающий ограничения pkey, то он получает сигнал SIGSEGV. Подробную информацию об этом сигнале смотрите в sigaction(2).

Чтобы использовать свойство pkeys, это должен поддерживать процессор, а ядро должно включать поддержку этого свойства для этого процессора. К началу 2016 года это относится только к будущим процессорам Intel x86, и данная аппаратура поддерживает 16 ключей защиты на каждый процесс. Однако pkey 0 используется как ключ по умолчанию, поэтому для приложения доступно только 15. Ключ по умолчанию назначается любой области памяти, для которой pkey не был назначен явным образом с помощью pkey_mprotect(2).

Потенциально, ключи защиты могут добавить уровень безопасности и надежности приложений. Но, прежде всего, они не разрабатывались как средство защиты. Например, WRPKRU — это полностью непривилегированная инструкция, поэтому pkeys бесполезны, когда атакующий контролирует регистр PKRU или может выполнять любые инструкции.

Приложения должны следить за тем, чтобы их ключи защиты не «не утекли». Например, перед вызовом pkey_free(2) приложение должно проверить, что pkey не назначен памяти. Если приложение оставит назначенным освобождённый pkey, то будущий пользователь этого pkey может непреднамеренно изменить права на не относящуюся к делу структуру данных, что может привести к проблемам с безопасностью или стабильностью. В настоящее время ядро позволяет вызывать pkey_free(2) для задействованных pkeys, так как выполнение дополнительных проверок повлияло бы на производительность процессора или памяти. Реализация необходимых проверок переложена на приложение. Приложения могут найти области памяти, которым назначен pkey, в файле /proc/[pid]/smaps. Дополнительная информация представлена в proc(5).

Приложение, которое хочет воспользоваться ключами защиты, может работать и без них. Ключи могут быть недоступны из-за отсутствия аппаратной поддержки системе, где запускается приложение, в коде ядра может не быть поддержки, поддержка в ядре может быть выключена или все ключи уже задействованы библиотекой, которую использует приложение. В приложениях рекомендуется просто вызывать pkey_alloc(2) и проверять успешность выполнения, а не пытаться проверять наличие поддержки каким-то другим образом.

Хотя и необязательно, поддержку ключей защиты в аппаратуре можно определить помощью инструкции cpuid. От том, как это сделать, смотрите в программном руководстве разработчика Intel. Ядро определяет наличие поддержки и выводит информацию в /proc/cpuinfo в поле «flags». Строка «pku» в этом поле означает, что аппаратура поддерживает ключи защиты, а строка «ospke» означает, что ядро содержит включённую поддержку защиты.

Если приложение использует нити и ключи защиты, то нужно быть особенно осторожным. Нити наследуют права ключей защиты родителя при выполнении системного вызова clone(2). Приложения должны убедиться, что их собственные права подходят для дочерних нитей до вызова clone(2) или выполнять инициализацию прав ключей защиты в самих нитях.

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

Данное поведение сигнала необычно из-за того, что регистр x86 PKRU (который хранит права доступа ключа защиты) управляется тем же аппаратным механизмом (XSAVE) что и регистры плавающей запятой. Поведение сигнала такое же как у регистров плавающей запятой.

### Системные вызовы ключей защиты
В ядре Linux реализованы следующие системные вызовы для работы с pkey: pkey_mprotect(2), pkey_alloc(2) и pkey_free(2).

Системные вызовы Linux pkey доступны только, если ядро было собрано с включённым параметром CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS.

## ПРИМЕР
Программа, представленная далее, выделяет страницу памяти с правами на чтение и запись. Затем она записывает кусок данных в памяти и читает его. После этого она пытается выделить ключ защиты и запретить доступ к странице с помощью инструкции WRPKRU. Далее она пытается получить доступ к странице, что, как мы ожидаем, вызовет сигнал завершения приложения.

```
$ ./a.out
буфер содержит: 73
читаем буфер снова...
Segmentation fault (core dumped)
```

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

```
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <sys/mman.h>
static inline void
wrpkru(unsigned int pkru)
{

    unsigned int eax = pkru;

    unsigned int ecx = 0;

    unsigned int edx = 0;

    asm volatile(".byte 0x0f,0x01,0xef\n\t"

                 : : "a" (eax), "c" (ecx), "d" (edx));
}
int
pkey_set(int pkey, unsigned long rights, unsigned long flags)
{

    unsigned int pkru = (rights << (2 * pkey));

    return wrpkru(pkru);
}
int
pkey_mprotect(void *ptr, size_t size, unsigned long orig_prot,

              unsigned long pkey)
{

    return syscall(SYS_pkey_mprotect, ptr, size, orig_prot, pkey);
}
int
pkey_alloc(void)
{

    return syscall(SYS_pkey_alloc, 0, 0);
}
int
pkey_free(unsigned long pkey)
{

    return syscall(SYS_pkey_free, pkey);
}
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \

                           } while (0)
int
main(void)
{

    int status;

    int pkey;

    int *buffer;

    /*

     * выделяем страницу памяти

     */

    buffer = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE,

                  MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);

    if (buffer == MAP_FAILED)

        errExit("mmap");

    /*

     * пишем произвольные данные в страницу (чуть)

     */

    *buffer = __LINE__;

    printf("буфер содержит: %d\n", *buffer);

    /*

     * выделяем ключ защиты:

     */

    pkey = pkey_alloc();

    if (pkey == -1)

        errExit("pkey_alloc");

    /*

     * запрещаем доступ к памяти, на которой будет установлен «pkey»,

     * хотя пока ничего не запрещено

     */

    status = pkey_set(pkey, PKEY_DISABLE_ACCESS, 0);

    if (status)

        errExit("pkey_set");

    /*

     * установим ключ защиты на «буфер»

     * заметим, что он доступен пока не применён mprotect()

     * и ключ не заменен созданным ранее pkey_set()

     */

    status = pkey_mprotect(buffer, getpagesize(),

                           PROT_READ | PROT_WRITE, pkey);

    if (status == -1)

        errExit("pkey_mprotect");

    printf("читаем буфер снова...\n");

    /*

     * приложение падает, так как мы запретили доступ

     */

    printf("буфер содержит: %d\n", *buffer);

    status = pkey_free(pkey);

    if (status == -1)

        errExit("pkey_free");

    exit(EXIT_SUCCESS);
}
```

## СМОТРИТЕ ТАКЖЕ
pkey_alloc(2), pkey_free(2), pkey_mprotect(2), sigaction(2)


posixoptions

title: posixoptions(7)

summary: необязательные части стандарта POSIX

text:
# posixoptions(7)

## ИМЯ
posixoptions - необязательные части стандарта POSIX

## ОПИСАНИЕ
В стандарте POSIX (информация взята POSIX.1-2001) описан набор правил работы и интерфейсы, требуемый от совместимой системы. Однако много интерфейсов являются необязательными и имеется набор макросов тестирования свойств для проверки доступности интерфейсов во время компиляции, а также есть функции sysconf(3), fpathconf(3), pathconf(3), confstr(3), которые выполняют проверки во время выполнения. Из сценариев оболочки можно использовать getconf(1). Подробности смотрите в sysconf(3).

Мы приводим имя из POSIX, свойство, имя параметра sysconf(3), который используется для запроса этого свойство, и возможно, очень краткое описание. Более полную информацию можно найти в самом стандарте POSIX, из версий, которые теперь свободно доступны через веб.

### ADV - _POSIX_ADVISORY_INFO - _SC_ADVISORY_INFO
Доступны следующие консультативные функции:

```
posix_fadvise()
posix_fallocate()
posix_memalign()
posix_madvise()
```

### AIO - _POSIX_ASYNCHRONOUS_IO - _SC_ASYNCHRONOUS_IO
Доступен заголовочный файл <aio.h>. Доступны следующие функции:

```
aio_cancel()
aio_error()
aio_fsync()
aio_read()
aio_return()
aio_suspend()
aio_write()
lio_listio()
```

### BAR - _POSIX_BARRIERS - _SC_BARRIERS
Это свойство подразумевает свойства _POSIX_THREADS и _POSIX_THREAD_SAFE_FUNCTIONS. Доступны следующие функции:

```
pthread_barrier_destroy()
pthread_barrier_init()
pthread_barrier_wait()
pthread_barrierattr_destroy()
pthread_barrierattr_init()
```

### --- - POSIX_CHOWN_RESTRICTED
Если действует это свойство (всегда, согласно POSIX.1-2001), то только суперпользователь может изменять владельца файла, а обычный пользователь может задать группу файла только на одну из групп, которой принадлежит. Учитывается в функциях:

```
chown()
fchown()
```

### CS - _POSIX_CLOCK_SELECTION - _SC_CLOCK_SELECTION
Это свойство подразумевает свойство _POSIX_TIMERS. Доступны следующие функции:

```
pthread_condattr_getclock()
pthread_condattr_setclock()
clock_nanosleep()
```

Если CLOCK_REALTIME изменяется функцией clock_settime(), то это влияет на все таймеры, заданные абсолютным временем.

### CPT - _POSIX_CPUTIME - _SC_CPUTIME
Поддерживается идентификатор часов CLOCK_PROCESS_CPUTIME_ID. Начальное значение этих часов равно нулю для каждого процесса. Данное свойство подразумевает свойство _POSIX_TIMERS. Доступна функция clock_getcpuclockid().

### --- - _POSIX_FILE_LOCKING - _SC_FILE_LOCKING
Эта функция была удалена. Нет в окончательной XPG6.

### FSC - _POSIX_FSYNC - _SC_FSYNC
Доступна функция fsync().

### IP6 - _POSIX_IPV6 - _SC_IPV6
Поддерживается Internet Protocol Version 6.

### --- - _POSIX_JOB_CONTROL - _SC_JOB_CONTROL
Если доступно это свойство (всегда в POSIX.1-2001), то в системе реализовано управление заданиями в стиле POSIX и доступны следующие функции:

```
setpgid()
tcdrain()
tcflush()
tcgetpgrp()
tcsendbreak()
tcsetattr()
tcsetpgrp()
```

### MF - _POSIX_MAPPED_FILES - _SC_MAPPED_FILES
Поддерживается общая память. Доступен заголовочный файл <sys/mman.h>. Доступны следующие функции:

```
mmap()
msync()
munmap()
```

### ML - _POSIX_MEMLOCK - _SC_MEMLOCK
Общая память может блокироваться в ядре (core). Доступны следующие функции:

```
mlockall()
munlockall()
```

### MR/MLR - _POSIX_MEMLOCK_RANGE - _SC_MEMLOCK_RANGE
Более точно, диапазоны могут блокироваться в ядре (core). Доступны следующие функции:

```
mlock()
munlock()
```

### MPR - _POSIX_MEMORY_PROTECTION - _SC_MEMORY_PROTECTION
Доступна функция mprotect().

### MSG - _POSIX_MESSAGE_PASSING - _SC_MESSAGE_PASSING
Доступен заголовочный файл <mqueue.h>. Доступны следующие функции:

```
mq_close()
mq_getattr()
mq_notify()
mq_open()
mq_receive()
mq_send()
mq_setattr()
mq_unlink()
```

### MON - _POSIX_MONOTONIC_CLOCK - _SC_MONOTONIC_CLOCK
Поддерживается CLOCK_MONOTONIC. Это свойство подразумевает свойство _POSIX_TIMERS. Влияет на следующие функции:

```
aio_suspend()
clock_getres()
clock_gettime()
clock_settime()
timer_create()
```

### --- - _POSIX_MULTI_PROCESS - _SC_MULTI_PROCESS
Эта функция была удалена. Нет в окончательной XPG6.

### --- - _POSIX_NO_TRUNC
Если доступно это свойство (всегда в POSIX.1-2001), то компоненты пути длиннее чем NAME_MAX не обрезаются, а выдаётся ошибка. Данное свойство может зависеть от префикса компонента пути.

### PIO - _POSIX_PRIORITIZED_IO - _SC_PRIORITIZED_IO
Это свойство показывает, то можно задавать приоритеты для асинхронного ввода-вывода. Влияет на следующие функции:

```
aio_read()
aio_write()
```

### PS - _POSIX_PRIORITY_SCHEDULING - _SC_PRIORITY_SCHEDULING
Доступен заголовочный файл <sched.h>. Доступны следующие функции:

```
sched_get_priority_max()
sched_get_priority_min()
sched_getparam()
sched_getscheduler()
sched_rr_get_interval()
sched_setparam()
sched_setscheduler()
sched_yield()
```

Если также доступно свойство _POSIX_SPAWN, доступны следующие функции:

```
posix_spawnattr_getschedparam()
posix_spawnattr_getschedpolicy()
posix_spawnattr_setschedparam()
posix_spawnattr_setschedpolicy()
```

### RS - _POSIX_RAW_SOCKETS
Поддерживаются неструктурированные сокеты. Влияет на следующие функции:

```
getsockopt()
setsockopt()
```

### --- - _POSIX_READER_WRITER_LOCKS - _SC_READER_WRITER_LOCKS
Это свойство подразумевает свойство _POSIX_THREADS. И наоборот, согласно POSIX.1-2001, свойство _POSIX_THREADS подразумевает это свойство.

Доступны следующие функции:

```
pthread_rwlock_destroy()
pthread_rwlock_init()
pthread_rwlock_rdlock()
pthread_rwlock_tryrdlock()
pthread_rwlock_trywrlock()
pthread_rwlock_unlock()
pthread_rwlock_wrlock()
pthread_rwlockattr_destroy()
pthread_rwlockattr_init()
```

### RTS - _POSIX_REALTIME_SIGNALS - _SC_REALTIME_SIGNALS
Доступны сигналы реального времени. Доступны следующие функции:

```
sigqueue()
sigtimedwait()
sigwaitinfo()
```

### --- - _POSIX_REGEXP - _SC_REGEXP
Если доступно это свойство (всегда в POSIX.1-2001), то поддерживаются регулярные выражения POSIX и доступны следующие функции:

```
regcomp()
regerror()
regexec()
regfree()
```

### --- - _POSIX_SAVED_IDS - _SC_SAVED_IDS
Если доступно это свойство (всегда в POSIX.1-2001), то у процесса имеются сохранённый set-user-ID и сохранённый set-group-ID. Влияет на следующие функции:

```
exec()
kill()
seteuid()
setegid()
setgid()
setuid()
```

### SEM - _POSIX_SEMAPHORES - _SC_SEMAPHORES
Доступен заголовочный файл <semaphore.h>. Доступны следующие функции:

```
sem_close()
sem_destroy()
sem_getvalue()
sem_init()
sem_open()
sem_post()
sem_trywait()
sem_unlink()
sem_wait()
```

### SHM - _POSIX_SHARED_MEMORY_OBJECTS - _SC_SHARED_MEMORY_OBJECTS
Доступны следующие функции:

```
mmap()
munmap()
shm_open()
shm_unlink()
```

### --- - _POSIX_SHELL - _SC_SHELL
Если доступно это свойство (всегда в POSIX.1-2001), то в системе доступна функция system().

### SPN - _POSIX_SPAWN - _SC_SPAWN
Данное свойство выделяет процесс создания поддержки в связи с тем, что трудно или невозможно использовать fork(), например, из-за отсутствия MMU.

Если задействовано свойство _POSIX_SPAWN, то доступен заголовочный файл <spawn.h> и следующие функции:

```
posix_spawn()
posix_spawn_file_actions_addclose()
posix_spawn_file_actions_adddup2()
posix_spawn_file_actions_addopen()
posix_spawn_file_actions_destroy()
posix_spawn_file_actions_init()
posix_spawnattr_destroy()
posix_spawnattr_getsigdefault()
posix_spawnattr_getflags()
posix_spawnattr_getpgroup()
posix_spawnattr_getsigmask()
posix_spawnattr_init()
posix_spawnattr_setsigdefault()
posix_spawnattr_setflags()
posix_spawnattr_setpgroup()
posix_spawnattr_setsigmask()
posix_spawnp()
```

Если также доступно свойство _POSIX_PRIORITY_SCHEDULING, то доступны следующие функции:

```
posix_spawnattr_getschedparam()
posix_spawnattr_getschedpolicy()
posix_spawnattr_setschedparam()
posix_spawnattr_setschedpolicy()
```

### SPI - _POSIX_SPIN_LOCKS - _SC_SPIN_LOCKS
Это свойство подразумевает свойства _POSIX_THREADS и _POSIX_THREAD_SAFE_FUNCTIONS. Доступны следующие функции:

```
pthread_spin_destroy()
pthread_spin_init()
pthread_spin_lock()
pthread_spin_trylock()
pthread_spin_unlock()
```

### SS - _POSIX_SPORADIC_SERVER - _SC_SPORADIC_SERVER
Поддерживается алгоритм планирования SCHED_SPORADIC. Это свойство подразумевает свойство _POSIX_PRIORITY_SCHEDULING. Влияет на следующие функции:

```
sched_setparam()
sched_setscheduler()
```

### SIO - _POSIX_SYNCHRONIZED_IO - _SC_SYNCHRONIZED_IO
Влияет на следующие функции:

```
open()
msync()
fsync()
fdatasync()
```

### TSA - _POSIX_THREAD_ATTR_STACKADDR - _SC_THREAD_ATTR_STACKADDR
Влияет на следующие функции:

```
pthread_attr_getstack()
pthread_attr_getstackaddr()
pthread_attr_setstack()
pthread_attr_setstackaddr()
```

### TSS - _POSIX_THREAD_ATTR_STACKSIZE - _SC_THREAD_ATTR_STACKSIZE
Влияет на следующие функции:

```
pthread_attr_getstack()
pthread_attr_getstacksize()
pthread_attr_setstack()
pthread_attr_setstacksize()
```

### TCT - _POSIX_THREAD_CPUTIME - _SC_THREAD_CPUTIME
Поддерживается идентификатор часов CLOCK_THREAD_CPUTIME_ID. Это свойство подразумевает свойство _POSIX_TIMERS. Влияет на следующие функции:

```
pthread_getcpuclockid()
clock_getres()
clock_gettime()
clock_settime()
timer_create()
```

### TPI - _POSIX_THREAD_PRIO_INHERIT - _SC_THREAD_PRIO_INHERIT
Влияет на следующие функции:

```
pthread_mutexattr_getprotocol()
pthread_mutexattr_setprotocol()
```

### TPP - _POSIX_THREAD_PRIO_PROTECT - _SC_THREAD_PRIO_PROTECT
Влияет на следующие функции:

```
pthread_mutex_getprioceiling()
pthread_mutex_setprioceiling()
pthread_mutexattr_getprioceiling()
pthread_mutexattr_getprotocol()
pthread_mutexattr_setprioceiling()
pthread_mutexattr_setprotocol()
```

### TPS - _POSIX_THREAD_PRIORITY_SCHEDULING - _SC_THREAD_PRIORITY_SCHEDULING
Если доступно это свойство, то нити в процессе можно выполнять с разными приоритетами или планировщиками. Влияет на следующие функции:

```
pthread_attr_getinheritsched()
pthread_attr_getschedpolicy()
pthread_attr_getscope()
pthread_attr_setinheritsched()
pthread_attr_setschedpolicy()
pthread_attr_setscope()
pthread_getschedparam()
pthread_setschedparam()
pthread_setschedprio()
```

### TSH - _POSIX_THREAD_PROCESS_SHARED - _SC_THREAD_PROCESS_SHARED
Влияет на следующие функции:

```
pthread_barrierattr_getpshared()
pthread_barrierattr_setpshared()
pthread_condattr_getpshared()
pthread_condattr_setpshared()
pthread_mutexattr_getpshared()
pthread_mutexattr_setpshared()
pthread_rwlockattr_getpshared()
pthread_rwlockattr_setpshared()
```

### TSF - _POSIX_THREAD_SAFE_FUNCTIONS - _SC_THREAD_SAFE_FUNCTIONS
Влияет на следующие функции:

```
readdir_r()
getgrgid_r()
getgrnam_r()
getpwnam_r()
getpwuid_r()
flockfile()
ftrylockfile()
funlockfile()
getc_unlocked()
getchar_unlocked()
putc_unlocked()
putchar_unlocked()
rand_r()
strerror_r()
strtok_r()
asctime_r()
ctime_r()
gmtime_r()
localtime_r()
```

### TSP - _POSIX_THREAD_SPORADIC_SERVER - _SC_THREAD_SPORADIC_SERVER
Это свойство подразумевает свойство _POSIX_THREAD_PRIORITY_SCHEDULING. Влияет на следующие функции:

```
sched_getparam()
sched_setparam()
sched_setscheduler()
```

### THR - _POSIX_THREADS - _SC_THREADS
Доступна начальная поддержка нитей POSIX. Доступны следующие функции:

```
pthread_atfork()
pthread_attr_destroy()
pthread_attr_getdetachstate()
pthread_attr_getschedparam()
pthread_attr_init()
pthread_attr_setdetachstate()
pthread_attr_setschedparam()
pthread_cancel()
pthread_cleanup_push()
pthread_cleanup_pop()
pthread_cond_broadcast()
pthread_cond_destroy()
pthread_cond_init()
pthread_cond_signal()
pthread_cond_timedwait()
pthread_cond_wait()
pthread_condattr_destroy()
pthread_condattr_init()
pthread_create()
pthread_detach()
pthread_equal()
pthread_exit()
pthread_getspecific()
pthread_join()
pthread_key_create()
pthread_key_delete()
pthread_mutex_destroy()
pthread_mutex_init()
pthread_mutex_lock()
pthread_mutex_trylock()
pthread_mutex_unlock()
pthread_mutexattr_destroy()
pthread_mutexattr_init()
pthread_once()
pthread_rwlock_destroy()
pthread_rwlock_init()
pthread_rwlock_rdlock()
pthread_rwlock_tryrdlock()
pthread_rwlock_trywrlock()
pthread_rwlock_unlock()
pthread_rwlock_wrlock()
pthread_rwlockattr_destroy()
pthread_rwlockattr_init()
pthread_self()
pthread_setcancelstate()
pthread_setcanceltype()
pthread_setspecific()
pthread_testcancel()
```

### TMO - _POSIX_TIMEOUTS - _SC_TIMEOUTS
Доступны следующие функции:

```
mq_timedreceive()
mq_timedsend()
pthread_mutex_timedlock()
pthread_rwlock_timedrdlock()
pthread_rwlock_timedwrlock()
sem_timedwait()
posix_trace_timedgetnext_event()
```

### TMR - _POSIX_TIMERS - _SC_TIMERS
Доступны следующие функции:

```
clock_getres()
clock_gettime()
clock_settime()
nanosleep()
timer_create()
timer_delete()
timer_gettime()
timer_getoverrun()
timer_settime()
```

### TRC - _POSIX_TRACE - _SC_TRACE
Доступна поддержка трассировки POSIX. Доступны следующие функции:

```
posix_trace_attr_destroy()
posix_trace_attr_getclockres()
posix_trace_attr_getcreatetime()
posix_trace_attr_getgenversion()
posix_trace_attr_getmaxdatasize()
posix_trace_attr_getmaxsystemeventsize()
posix_trace_attr_getmaxusereventsize()
posix_trace_attr_getname()
posix_trace_attr_getstreamfullpolicy()
posix_trace_attr_getstreamsize()
posix_trace_attr_init()
posix_trace_attr_setmaxdatasize()
posix_trace_attr_setname()
posix_trace_attr_setstreamsize()
posix_trace_attr_setstreamfullpolicy()
posix_trace_clear()
posix_trace_create()
posix_trace_event()
posix_trace_eventid_equal()
posix_trace_eventid_get_name()
posix_trace_eventid_open()
posix_trace_eventtypelist_getnext_id()
posix_trace_eventtypelist_rewind()
posix_trace_flush()
posix_trace_get_attr()
posix_trace_get_status()
posix_trace_getnext_event()
posix_trace_shutdown()
posix_trace_start()
posix_trace_stop()
posix_trace_trygetnext_event()
```

### TEF - _POSIX_TRACE_EVENT_FILTER - _SC_TRACE_EVENT_FILTER
Это свойство подразумевает свойство _POSIX_TRACE. Доступны следующие функции:

```
posix_trace_eventset_add()
posix_trace_eventset_del()
posix_trace_eventset_empty()
posix_trace_eventset_fill()
posix_trace_eventset_ismember()
posix_trace_get_filter()
posix_trace_set_filter()
posix_trace_trid_eventid_open()
```

### TRI - _POSIX_TRACE_INHERIT - _SC_TRACE_INHERIT
Поддерживается трассировка потомков трассируемого процесса. Это свойство подразумевает свойство _POSIX_TRACE. Доступны следующие функции:

```
posix_trace_attr_getinherited()
posix_trace_attr_setinherited()
```

### TRL - _POSIX_TRACE_LOG - _SC_TRACE_LOG
Это свойство подразумевает свойство _POSIX_TRACE. Доступны следующие функции:

```
posix_trace_attr_getlogfullpolicy()
posix_trace_attr_getlogsize()
posix_trace_attr_setlogfullpolicy()
posix_trace_attr_setlogsize()
posix_trace_close()
posix_trace_create_withlog()
posix_trace_open()
posix_trace_rewind()
```

### TYM - _POSIX_TYPED_MEMORY_OBJECTS - _SC_TYPED_MEMORY_OBJECT
Доступны следующие функции:

```
posix_mem_offset()
posix_typed_mem_get_info()
posix_typed_mem_open()
```

### --- - _POSIX_VDISABLE
Имеется всегда (вероятное значение — 0). Присвоение значения специального управляющего символа означает выключение.

## РАСШИРЕНИЯ X/OPEN SYSTEM INTERFACE

### XSI - _XOPEN_CRYPT - _SC_XOPEN_CRYPT
Доступны следующие функции:

```
crypt()
encrypt()
setkey()
```

### XSI - _XOPEN_REALTIME - _SC_XOPEN_REALTIME
Это свойство подразумевает следующие свойства:

_POSIX_ASYNCHRONOUS_IO==200112L

_POSIX_FSYNC

_POSIX_MAPPED_FILES

_POSIX_MEMLOCK==200112L

_POSIX_MEMLOCK_RANGE==200112L

_POSIX_MEMORY_PROTECTION

_POSIX_MESSAGE_PASSING==200112L

_POSIX_PRIORITIZED_IO

_POSIX_PRIORITY_SCHEDULING==200112L

_POSIX_REALTIME_SIGNALS==200112L

_POSIX_SEMAPHORES==200112L

_POSIX_SHARED_MEMORY_OBJECTS==200112L

_POSIX_SYNCHRONIZED_IO==200112L

_POSIX_TIMERS==200112L

### ADV - --- - ---
Группа свойств Advanced Realtime подразумевает, что все следующие свойства определены до 200112L:

_POSIX_ADVISORY_INFO

_POSIX_CLOCK_SELECTION

(подразумевает _POSIX_TIMERS)

_POSIX_CPUTIME

(подразумевает _POSIX_TIMERS)

_POSIX_MONOTONIC_CLOCK

(подразумевает _POSIX_TIMERS)

_POSIX_SPAWN

_POSIX_SPORADIC_SERVER

(подразумевает _POSIX_PRIORITY_SCHEDULING)

_POSIX_TIMEOUTS

_POSIX_TYPED_MEMORY_OBJECTS

### XSI - _XOPEN_REALTIME_THREADS - _SC_XOPEN_REALTIME_THREADS
Это свойство подразумевает, что все следующие свойства определены до 200112L:

_POSIX_THREAD_PRIO_INHERIT

_POSIX_THREAD_PRIO_PROTECT

_POSIX_THREAD_PRIORITY_SCHEDULING

### ADVANCED REALTIME THREADS - --- - ---
Это свойство подразумевает, что все следующие свойства определены до 200112L:

_POSIX_BARRIERS

(подразумевает _POSIX_THREADS, _POSIX_THREAD_SAFE_FUNCTIONS)

_POSIX_SPIN_LOCKS

(подразумевает _POSIX_THREADS, _POSIX_THREAD_SAFE_FUNCTIONS)

_POSIX_THREAD_CPUTIME

(подразумевает _POSIX_TIMERS)

_POSIX_THREAD_SPORADIC_SERVER

(подразумевает _POSIX_THREAD_PRIORITY_SCHEDULING)

### TRACING - --- - ---
Это свойство подразумевает, что все следующие свойства определены до 200112L:

_POSIX_TRACE

_POSIX_TRACE_EVENT_FILTER

_POSIX_TRACE_LOG

_POSIX_TRACE_INHERIT

### STREAMS - _XOPEN_STREAMS - _SC_XOPEN_STREAMS
Доступны следующие функции:

```
fattach()
fdetach()
getmsg()
getpmsg()
ioctl()
isastream()
putmsg()
putpmsg()
```

### XSI - _XOPEN_LEGACY - _SC_XOPEN_LEGACY
Функции, включённые в группу устаревших свойств, которые были обязательны ранее, но в этой версии стали необязательными. Это относится к следующим функциям:

```
bcmp()
bcopy()
bzero()
ecvt()
fcvt()
ftime()
gcvt()
getcwd()
index()
mktemp()
rindex()
utimes()
wcswcs()
```

### XSI - _XOPEN_UNIX - _SC_XOPEN_UNIX
Доступны следующие функции:

```
mmap()
munmap()
msync()
```

Это свойство подразумевает следующие свойства:

_POSIX_FSYNC

_POSIX_MAPPED_FILES

_POSIX_MEMORY_PROTECTION

_POSIX_THREAD_ATTR_STACKADDR

_POSIX_THREAD_ATTR_STACKSIZE

_POSIX_THREAD_PROCESS_SHARED

_POSIX_THREAD_SAFE_FUNCTIONS

_POSIX_THREADS

Это свойство может подразумевать следующие свойства из групп свойств XSI:

Шифрование (_XOPEN_CRYPT)

Realtime (_XOPEN_REALTIME)

Advanced Realtime (ADB)

Realtime Threads (_XOPEN_REALTIME_THREADS)

Advanced Realtime Threads (ADVANCED REALTIME THREADS)

Tracing (TRACING)

XSI Streams (STREAMS)

Legacy (_XOPEN_LEGACY)

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


process-keyring

title: process-keyring(7)

summary: общая связка ключей для процесса

text:
# process-keyring(7)

## ИМЯ
process-keyring - общая связка ключей для процесса

## ОПИСАНИЕ
Связка ключей процесса — это связка ключей, используемая для привязки ключей процесса. Она создаётся только по запросу процесса. Связка ключей процесса имеет имя (описание) _pid.

Существует специальное значение, KEY_SPEC_PROCESS_KEYRING, которое можно использовать вместо настоящего серийного номера связки ключей процесса вызывающего процесса.

В утилите keyctl(1) подобным образом можно использовать «@p» вместо числового ID ключа, но так как keyctl(1) выполняется после разветвления, это не используется.

Нить, создаваемая clone(2) с флагом CLONE_THREAD, имеет ту же связку ключей процесса, что и вызвавший clone(2). Если новый процесс создаётся с помощью fork(), то изначально он не имеет связки ключей процесса. Связка ключей процесса очищается при execve(2). Связка ключей процесса уничтожается когда завершается последняя нить, которая на неё ссылалась.

Если процесс не имеет связки ключей процесса, когда к ней обращается, то она будет создана, если запрашивается изменение связки ключей; в противном случае возвращается ошибка ENOKEY.

## СМОТРИТЕ ТАКЖЕ
keyctl(1), keyctl(3), keyrings(7), persistent-keyring(7), session-keyring(7), thread-keyring(7), user-keyring(7), user-session-keyring(7)


pthreads

title: pthreads(7)

summary: нити POSIX

text:
# pthreads(7)

## ИМЯ
pthreads - нити POSIX

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

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

- идентификатор процесса

- идентификатор родительского процесса

- Идентификатор группы процессов и сеанса

- Управляющий терминал

- Идентификаторы пользователя и группы

- Открытые файловые дескрипторы

- Обычные блокировки (смотрите fcntl(2))

- Обработчики сигналов

- Маска создания режима доступа к файлу (umask(2))

- Текущий каталог (chdir(2)) и корневой каталог (chroot(2))

- Интервальные таймеры (setitimer(2)) и таймеры POSIX (timer_create(2))

- Значение уступчивости (setpriority(2))

- Ограничения по ресурсам (setrlimit(2))

- Измерители потребления времени ЦП (times(2)) и ресурсов (getrusage(2))

Как и для стека, в POSIX.1 определены другие атрибуты, которые уникальны в каждой нити:

- Идентификатор нити (тип данных pthread_t)

- Маска сигналов (pthread_sigmask(3))

- Переменная errno

- Альтернативный стек сигнала (sigaltstack(2))

- Алгоритм и приоритет планирования реального времени (sched(7))

Следующие свойства есть только в Linux и также уникальны в каждой нити:

- мандаты (смотрите capabilities(7))

- Привязка к ЦП (sched_setaffinity(2))

### Возвращаемые значения из функций pthreads
Большинство функций pthreads при успешном выполнении возвращает 0 или номер ошибки в противном случае. Заметим, что функции pthreads не изменяют errno. Для каждой функции pthreads, которая может вернуть ошибку, в POSIX.1-2001 определено, что функция никогда не может завершиться с ошибкой EINTR.

### Идентификатор нити
Каждой нити процесса назначается уникальный идентификатор нити (имеет тип pthread_t). Этот идентификатор возвращается вызывающему pthread_create(3), а в самой нити её идентификатор можно получить с помощью pthread_self(3).

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

Система может повторно использовать идентификатор нити после объединения завершённой нити или отсоединения завершённой нити. В POSIX сказано: «Если приложение пытается использовать идентификатор нити, у который закончился срок жизни, то поведение не предсказуемо».

### Нитебезопасные функции
Нитебезопасная функция — это функция, которую можно безопасно (т. е., это приведёт к единым результатам независимо от окружения) вызывать из нескольких нитей одновременно.

В POSIX.1-2001 и POSIX.1-2008 требуется, чтобы все функции, описанные в стандарте, были нитебезопасными, за исключением следующих функций:

```
asctime()
basename()
catgets()
crypt()
ctermid() если передаётся аргумент не NULL
ctime()
dbm_clearerr()
dbm_close()
dbm_delete()
dbm_error()
dbm_fetch()
dbm_firstkey()
dbm_nextkey()
dbm_open()
dbm_store()
dirname()
dlerror()
drand48()
ecvt() [только POSIX.1-2001 (удалена из POSIX.1-2008)]
encrypt()
endgrent()
endpwent()
endutxent()
fcvt() [только POSIX.1-2001 (удалена из POSIX.1-2008)]
ftw()
gcvt() [только POSIX.1-2001 (удалена из POSIX.1-2008)]
getc_unlocked()
getchar_unlocked()
getdate()
getenv()
getgrent()
getgrgid()
getgrnam()
gethostbyaddr() [только POSIX.1-2001 (удалена из POSIX.1-2008)]
gethostbyname() [только POSIX.1-2001 (удалена из POSIX.1-2008)]
gethostent()
getlogin()
getnetbyaddr()
getnetbyname()
getnetent()
getopt()
getprotobyname()
getprotobynumber()
getprotoent()
getpwent()
getpwnam()
getpwuid()
getservbyname()
getservbyport()
getservent()
getutxent()
getutxid()
getutxline()
gmtime()
hcreate()
hdestroy()
hsearch()
inet_ntoa()
l64a()
lgamma()
lgammaf()
lgammal()
localeconv()
localtime()
lrand48()
mrand48()
nftw()
nl_langinfo()
ptsname()
putc_unlocked()
putchar_unlocked()
putenv()
pututxline()
rand()
readdir()
setenv()
setgrent()
setkey()
setpwent()
setutxent()
strerror()
strsignal() [добавлена в POSIX.1-2008]
strtok()
system() [добавлена в POSIX.1-2008]
tmpnam() если передаётся аргумент не NULL
ttyname()
unsetenv()
wcrtomb() если конечный аргумент NULL
wcsrtombs() если конечный аргумент NULL
wcstombs()
wctomb()
```

### Безопасные асинхронные отменяемые функции
Безопасная асинхронная отменяемая функция (async-cancel-safe function) — это функция, которую можно безопасно вызывать в приложении, в котором разрешено асинхронная отмена (смотрите pthread_setcancelstate(3)).

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

```
pthread_cancel()
pthread_setcancelstate()
pthread_setcanceltype()
```

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

Следующие функции должны быть точками отмены согласно POSIX.1-2001 и/или POSIX.1-2008:

```
accept()
aio_suspend()
clock_nanosleep()
close()
connect()
creat()
fcntl() F_SETLKW
fdatasync()
fsync()
getmsg()
getpmsg()
lockf() F_LOCK
mq_receive()
mq_send()
mq_timedreceive()
mq_timedsend()
msgrcv()
msgsnd()
msync()
nanosleep()
open()
openat() [добавлена в POSIX.1-2008]
pause()
poll()
pread()
pselect()
pthread_cond_timedwait()
pthread_cond_wait()
pthread_join()
pthread_testcancel()
putmsg()
putpmsg()
pwrite()
read()
readv()
recv()
recvfrom()
recvmsg()
select()
sem_timedwait()
sem_wait()
send()
sendmsg()
sendto()
sigpause() [только POSIX.1-2001 (перемещена в список «может» в POSIX.1-2008)]
sigsuspend()
sigtimedwait()
sigwait()
sigwaitinfo()
sleep()
system()
tcdrain()
usleep() [только POSIX.1-2001 (функция удалена в POSIX.1-2008)]
wait()
waitid()
waitpid()
write()
writev()
```

Следующие функции могут быть точками отмены согласно POSIX.1-2001 и/или POSIX.1-2008:

```
access()
asctime()
asctime_r()
catclose()
catgets()
catopen()
chmod() [добавлена в POSIX.1-2008]
chown() [добавлена в POSIX.1-2008]
closedir()
closelog()
ctermid()
ctime()
ctime_r()
dbm_close()
dbm_delete()
dbm_fetch()
dbm_nextkey()
dbm_open()
dbm_store()
dlclose()
dlopen()
dprintf() [добавлена в POSIX.1-2008]
endgrent()
endhostent()
endnetent()
endprotoent()
endpwent()
endservent()
endutxent()
faccessat() [добавлена в POSIX.1-2008]
fchmod() [добавлена в POSIX.1-2008]
fchmodat() [добавлена в POSIX.1-2008]
fchown() [добавлена в POSIX.1-2008]
fchownat() [Added in POSIX.1-2008]
fclose()
fcntl() (для любого значения аргумента cmd)
fflush()
fgetc()
fgetpos()
fgets()
fgetwc()
fgetws()
fmtmsg()
fopen()
fpathconf()
fprintf()
fputc()
fputs()
fputwc()
fputws()
fread()
freopen()
fscanf()
fseek()
fseeko()
fsetpos()
fstat()
fstatat() [добавлена в POSIX.1-2008]
ftell()
ftello()
ftw()
futimens() [добавлена в POSIX.1-2008]
fwprintf()
fwrite()
fwscanf()
getaddrinfo()
getc()
getc_unlocked()
getchar()
getchar_unlocked()
getcwd()
getdate()
getdelim() [добавлена в POSIX.1-2008]
getgrent()
getgrgid()
getgrgid_r()
getgrnam()
getgrnam_r()
gethostbyaddr() [только SUSv3 (функция удалена из POSIX.1-2008)]
gethostbyname() [только SUSv3 (функция удалена из POSIX.1-2008)]
gethostent()
gethostid()
gethostname()
getline() [добавлена в POSIX.1-2008]
getlogin()
getlogin_r()
getnameinfo()
getnetbyaddr()
getnetbyname()
getnetent()
getopt() (если opterr не равно 0)
getprotobyname()
getprotobynumber()
getprotoent()
getpwent()
getpwnam()
getpwnam_r()
getpwuid()
getpwuid_r()
gets()
getservbyname()
getservbyport()
getservent()
getutxent()
getutxid()
getutxline()
getwc()
getwchar()
getwd() [только SUSv3 (функция удалена из POSIX.1-2008)]
glob()
iconv_close()
iconv_open()
ioctl()
link()
linkat() [добавлена в POSIX.1-2008]
lio_listio() [добавлена в POSIX.1-2008]
localtime()
localtime_r()
lockf() [добавлена в POSIX.1-2008]
lseek()
lstat()
mkdir() [добавлена в POSIX.1-2008]
mkdirat() [добавлена в POSIX.1-2008]
mkdtemp() [добавлена в POSIX.1-2008]
mkfifo() [добавлена в POSIX.1-2008]
mkfifoat() [добавлена в POSIX.1-2008]
mknod() [добавлена в POSIX.1-2008]
mknodat() [добавлена в POSIX.1-2008]
mkstemp()
mktime()
nftw()
opendir()
openlog()
pathconf()
pclose()
perror()
popen()
posix_fadvise()
posix_fallocate()
posix_madvise()
posix_openpt()
posix_spawn()
posix_spawnp()
posix_trace_clear()
posix_trace_close()
posix_trace_create()
posix_trace_create_withlog()
posix_trace_eventtypelist_getnext_id()
posix_trace_eventtypelist_rewind()
posix_trace_flush()
posix_trace_get_attr()
posix_trace_get_filter()
posix_trace_get_status()
posix_trace_getnext_event()
posix_trace_open()
posix_trace_rewind()
posix_trace_set_filter()
posix_trace_shutdown()
posix_trace_timedgetnext_event()
posix_typed_mem_open()
printf()
psiginfo() [добавлена в POSIX.1-2008]
psignal() [добавлена в POSIX.1-2008]
pthread_rwlock_rdlock()
pthread_rwlock_timedrdlock()
pthread_rwlock_timedwrlock()
pthread_rwlock_wrlock()
putc()
putc_unlocked()
putchar()
putchar_unlocked()
puts()
pututxline()
putwc()
putwchar()
readdir()
readdir_r()
readlink() [добавлена в POSIX.1-2008]
readlinkat() [добавлена в POSIX.1-2008]
remove()
rename()
renameat() [добавлена в POSIX.1-2008]
rewind()
rewinddir()
scandir() [добавлена в POSIX.1-2008]
scanf()
seekdir()
semop()
setgrent()
sethostent()
setnetent()
setprotoent()
setpwent()
setservent()
setutxent()
sigpause() [добавлена в POSIX.1-2008]
stat()
strerror()
strerror_r()
strftime()
symlink()
symlinkat() [добавлена в POSIX.1-2008]
sync()
syslog()
tmpfile()
tmpnam()
ttyname()
ttyname_r()
tzset()
ungetc()
ungetwc()
unlink()
unlinkat() [добавлена в POSIX.1-2008]
utime() [добавлена в POSIX.1-2008]
utimensat() [добавлена в POSIX.1-2008]
utimes() [добавлена в POSIX.1-2008]
vdprintf() [добавлена в POSIX.1-2008]
vfprintf()
vfwprintf()
vprintf()
vwprintf()
wcsftime()
wordexp()
wprintf()
wscanf()
```

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

### Компиляция в Linux
В Linux, программы, использующие программный интерфейс pthreads, должны компилироваться с помощью cc -pthread.

### Реализации нитей POSIX в Linux
За всё время в библиотеке GNU C было две реализации нитей для Linux:

LinuxThreads

Первоначальная реализация pthreads. Начиная с glibc 2.4 эта реализация больше не поддерживается.

NPTL (библиотека нитей POSIX)

Современная реализация pthreads. По сравнению с LinuxThreads, NPTL более точно соответствует требованиям POSIX.1 и более производительна при создании большого количества нитей. NPTL появилась в glibc начиная с версии 2.3.2, и требует свойства, появившиеся в ядре Linux 2.6.

Обе реализации являются, так называемыми реализациями 1:1, то есть каждая нить отображается в планируемый элемента ядра. Обе реализации используют системный вызов Linux clone(2). В NPTL примитивы синхронизации нитей (мьютексы, объединение нитей и т .п.) реализованы с помощью системного вызова Linux futex(2).

### LinuxThreads
Отличительные свойства данной реализации:

- В дополнении к главной (начальной) нити, нити программы создаются с помощью pthread_create(3), реализация создаёт «управляющую» нить. Эта нить выполняет создание и завершение нитей (что приводит к проблемам, если эта нить случайно завершится).

- Внутри реализации используются сигналы. В Linux 2.2 и новее используются первые три сигнала реального времени (смотрите также signal(7)). В старых ядрах Linux используются сигналы SIGUSR1 и SIGUSR2. В приложениях нельзя использовать набор сигналов, задействованный в реализации.

- У нитей разные ID процесса (фактически, нити LinuxThreads реализованы как процессы, у которых больше общей информации чем обычно, но которые имеют разный идентификаторы процесса). Нити LinuxThreads (включая управляющую нить) в ps(1) видимы как отдельные процессы.

Реализация LinuxThreads отклоняется от спецификации POSIX.1 в нескольких местах, а именно:

- Вызов getpid(2) возвращает разные значения для каждой нити.

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

- Когда нить создаёт новый процесс-потомок с помощью fork(2), все нити должны ожидать потомка в wait(2). Однако реализация позволяет вызвать wait(2) только в нити, которая создала потомка.

- Когда нить вызывает execve(2), остальные нити завершают работу (требование POSIX.1). Однако, получаемый процесс имеет тот же PID, что и нить, которая вызвала execve(2): это должен быть тот же PID, что и у главной нити.

- У нитей разные ID пользователя и группы. Это может вызвать сложности в программах с set-user-ID и может привести к ошибкам функций pthreads, если приложение изменяет свои учётные данные с помощью seteuid(2) и подобных вызовов.

- У нитей разные ID сеанса и группы процессов.

- У нитей разные записи о блокировках, созданных fcntl(2).

- Информация, возвращаемая times(2) и getrusage(2), относится только к нити, а не к процессу в целом.

- У нитей разные значения отмен семафоров (смотрите semop(2)).

- У нитей разные интервалы таймеров.

- У нитей разные значения уступчивости.

- В POSIX.1 различаются сигналы, адресованные процессу в целом и отдельным нитям. Согласно POSIX.1, сигналы, направленные процессу (посланные, например, с помощью kill(2)), должны обрабатываться одной произвольно выбранной нитью внутри процесса. LinuxThreads не поддерживает сигналы, направленные процессу: сигналы могут посылаться только определённым нитям.

- Нити имеют разные настройки альтернативного стека сигналов. Однако, новые настройки альтернативного стека сигналов копируются из нити, которая его создаёт, так что изначально нити имеют единый альтернативный стек сигналов (новая нить должна запускаться без альтернативного стека сигналов. Если две нити обрабатывают сигналы в едином альтернативном стеке сигналов одновременно, то в программе возникнет непредсказуемая ошибка).

### NPTL
В NPTL все нити процесса помещаются в одну группу нитей; все члены группы нитей имеют один PID. В NPTL нет управляющей нити.

Внутри NPTL используются первые два сигнала реального времени; эти сигналы нельзя использовать в приложениях. Подробности смотрите в nptl(7).

NPTL тоже не соответствует POSIX.1, как минимум, в одном:

-

У нитей разные значения уступчивости.

Несколько несоответствий NPTL проявляется только при работе со старыми ядрами:

- Информация, возвращаемая times(2) и getrusage(2), относится только к нити, а не к процессу в целом (исправлено в ядре 2.6.9).

- У нитей разные ограничения по ресурсам (исправлено в ядре 2.6.10).

- У нитей разные интервалы таймеров (исправлено в ядре 2.6.12).

- Только из главной нити разрешено запускать новый сеанс с помощью setsid(2) (исправлено в версии 2.6.16).

- Только из главной нити разрешено делать процесс лидером группы процессов с помощью setpgid(2) (исправлено в версии 2.6.16).

- Нити имеют разные настройки альтернативного стека сигналов Однако, новые настройки альтернативного стека сигналов копируются из нити, которая его создаёт, так что изначально нити имеют единый альтернативный стек сигналов (исправлено в ядре 2.6.16).

Также стоит учитывать следующее о реализации NPTL:

-

Если мягкое ограничение ресурса на размер стека (смотрите описание RLIMIT_STACK в setrlimit(2)) устанавливается в значение, отличное от unlimited, то это значение определяет размер стека по умолчанию для новых нитей. В целях эффективности, это ограничение должно быть установлено но выполнения программы, возможно с помощью встроенной команды оболочки ulimit -s (limit stacksize в оболочке C).

### Определение реализации нитей
Начиная с glibc 2.3.2, для определение реализации нитей в системе можно использовать команду getconf(1), например:

```
bash$ getconf GNU_LIBPTHREAD_VERSION
NPTL 2.3.4
```

При наличии старых версий glibc можно использовать команду:

```
bash$ $( ldd /bin/ls | grep libc.so | awk '{print $3}' ) | \

                egrep -i 'threads|nptl'

        Native POSIX Threads Library by Ulrich Drepper et al
```

### Выбор реализации нитей: LD_ASSUME_KERNEL
В системах с glibc, которая поддерживает и LinuxThreads и NPTL (например, glibc 2.3.x), можно воспользоваться переменной окружения LD_ASSUME_KERNEL для замены выбранной динамическим компоновщиков реализации нитей по умолчанию. Эта переменная указывает динамическому компоновщику считать, что он запускается с определённой версией ядра в системе. Указав версию ядра, в которой не поддержки, требуемой NPTL, его можно заставить использовать LinuxThreads (наиболее вероятной причиной для этого будет необходимость запуска (сломанного) приложения, которое зависит от некоторого не совместимого поведения LinuxThreads). Пример:

```
bash$ $( LD_ASSUME_KERNEL=2.2.5 ldd /bin/ls | grep libc.so | \

                awk '{print $3}' ) | egrep -i 'threads|nptl'

        linuxthreads-0.10 by Xavier Leroy
```

## СМОТРИТЕ ТАКЖЕ
clone(2), fork(2), futex(2), gettid(2), proc(5), attributes(7), futex(7), nptl(7), sigevent(7), signal(7)

Различные справочные страницы pthreads, например: pthread_atfork(3), pthread_attr_init(3), pthread_cancel(3), pthread_cleanup_push(3), pthread_cond_signal(3), pthread_cond_wait(3), pthread_create(3), pthread_detach(3), pthread_equal(3), pthread_exit(3), pthread_key_create(3), pthread_kill(3), pthread_mutex_lock(3), pthread_mutex_unlock(3), pthread_mutexattr_destroy(3), pthread_mutexattr_init(3), pthread_once(3), pthread_spin_init(3), pthread_spin_lock(3), pthread_rwlockattr_setkind_np(3), pthread_setcancelstate(3), pthread_setcanceltype(3), pthread_setspecific(3), pthread_sigmask(3), pthread_sigqueue(3) и pthread_testcancel(3)