pty

title: pty(7)

summary: интерфейсы псевдо\-терминалов

text:
# pty(7)

## ИМЯ
pty - интерфейсы псевдо-терминалов

## ОПИСАНИЕ
Псевдо-терминал (иногда применяют сокращение «pty») — это пара виртуальных символьных устройств, которые предоставляют двунаправленный канал обмена. Один конец канала называется основным (master); другой конец канала называется подчинённым (slave). Подчинённый конец псевдо-терминала предоставляет интерфейс, который работает также как обычный классический терминал. Процесс, который управляется через терминал, может открыть подчинённый конец псевдо-терминала и затем управляться программой, которая открыла основной конец. Всё что пишется в основной конец поступает процессу на подчинённом конце так, как-будто данные вводились с терминала. Например, запись символа прерывания (обычно control-C) в основной конец приводит к генерации сигнала прерывания (SIGINT) для группы активных процессов, которая подключена к подчинённому концу. И наоборот, всё что записывается в в подчинённый конец псевдо-терминала, может быть прочитано процессом, который подключён к основному концу. Псевдо-терминалы используются такими приложениями как службы сетевого входа (ssh(1), rlogin(1), telnet(1)), эмуляторами терминалов xterm(1), script(1), screen(1), tmux(1), unbuffer(1) и expect(1).

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

Исторически существует два программных интерфейса для взаимодействия с псевдо-терминалами: BSD и System V. В SUSv1 стандартизирован программный интерфейс, основанный на программном интерфейсе System V, который должен применяться во всех новых программах, использующих псевдо-терминалы.

В Linux есть оба типа псевдо-терминалов — BSD и (стандартизированный) System V. В системах Linux терминалы System V часто называют псевдо-терминалами UNIX 98. Начиная с ядра версии 2.6.4 псевдо-терминалы BSD признаны устаревшими (их можно отключить во время настройки ядра). В новых программах следует использовать псевдо-терминалы UNIX 98.

### Псевдо-терминалы UNIX 98
Незадействованный основной псевдо-терминал UNIX 98 открывается вызовом posix_openpt(3) (эта функция открывает основное клонирующее устройство, /dev/ptmx; смотрите pts(4)). После выполнения специальной программной инициализации (с помощью grantpt(3) изменяется владелец и права на подчинённое устройство и с помощью unlockpt(3) разблокируется подчинённое устройство), соответствующее подчинённое устройство можно открыть, передав имя, полученное от ptsname(3), в вызов open(2).

Ядро Linux задаёт ограничение на количество доступных псевдо-терминалов UNIX 98. В ядрах до версии 2.6.3 включительно, это ограничение настраивалось при компиляции ядра (CONFIG_UNIX98_PTYS), и разрешалось 2048 псевдо-терминалов (по умолчанию 256). Начиная с версии 2.6.4, ограничение динамически настраивается через /proc/sys/kernel/pty/max, а в файле /proc/sys/kernel/pty/nr хранится количество уже используемых псевдо-терминалов. Подробности об этих двух файлах смотрите в proc(5).

### Псевдо-терминалы BSD
Псевдо-терминалы в стиле BSD предоставляются в виде заранее созданных пар, с именами вида /dev/ptyXY (основной) и /dev/ttyXY (подчинённый), где X это буква из 16-символьного набора [p-za-e], а Y это буква из 16-символьного набора [0-9a-f] (точный диапазон символов этих наборов отличается в разных реализациях UNIX). Например, /dev/ptyp1 и /dev/ttyp1 составляют псевдо-терминальную пару BSD. Процесс находит неиспользуемую псевдо-терминальную пару пробуя вызывать open(2) с каждым основным псевдо-терминалом, пока вызов не выполнится успешно. Затем может быть открыт соответствующий подчинённый псевдо-терминал (подставив «tty» вместо «pty» имени основного конца).

## ФАЙЛЫ
/dev/ptmx

основное клонирующее устройство UNIX 98

/dev/pts/*

подчинённые устройства UNIX 98

/dev/pty[p-za-e][0-9a-f]

основные устройства BSD

/dev/tty[p-za-e][0-9a-f]

подчинённые устройства BSD

## ЗАМЕЧАНИЯ
Описание запроса TIOCPKT ioctl(2), который управляет пакетным режимом, можно найти в ioctl_tty(2).

Вызовы ioctl(2) для BSD TIOCSTOP, TIOCSTART, TIOCUCNTL и TIOCREMOTE не реализованы в Linux.

## СМОТРИТЕ ТАКЖЕ
ioctl_tty(2), select(2), setsid(2), forkpty(3), openpty(3), termios(3), pts(4), tty(4)


random

package: man-pages-ru

title: random(7)

text:
# random(7)

## ИМЯ
random - обзор интерфейсов получения случайных чисел

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

Следующие интерфейсы предоставляют доступ к данным ядерного CSPRNG:

- Устройства /dev/urandom и /dev/random, описаны в random(4). Данные устройства доступны с первых версий Linux, а также они есть и во многих других системах.

- Системный вызов, который есть только в Linux — getrandom(2), доступен начиная с Linux 3.17. Данный вызов предоставляет доступ к источнику как у /dev/urandom (в этой странице упоминается как источник urandom) так и к источнику как у /dev/random (в этой странице упоминается как random). По умолчанию используется источник urandom; источник random выбирается при указании системному вызову флага GRND_RANDOM (функция getentropy(3) предоставляет схожий, более переносимый интерфейс, основанный на getrandom(2)).

### Инициализация пула энтропии
Ядро собирает биты энтропии из окружения. Когда собрано достаточное количество произвольных бит, пул энтропии считается инициализированным.

### Выбор источника случайных чисел
Если вы не генерируете долгосрочные ключи (и, скорее всего, и в этом случае), то, вероятно, не должны читать из устройства /dev/random или запускать getrandom(2) с флагом GRND_RANDOM. Вместо этого читайте устройство /dev/urandom и запускайте getrandom(2) без флага GRND_RANDOM. Алгоритмы шифрования, используемые для источника urandom, довольно консервативны, и поэтому их должно быть достаточно для любых нужд.

Недостаток GRND_RANDOM и чтения из /dev/random в том, что эта операция может заблокировать выполнение на неопределённый период времени. Более того, работа с частично выполненными запросами, которые могут вернуться при использовании GRND_RANDOM или чтении /dev/random, увеличивает сложность кода.

### Монте-Карло и другие вероятностные приложения выборки
Использование этих интерфейсов для предоставления большого количества данных при моделировании Монте-Карло или другим программам/алгоритмам, выполняющим вероятностную выборку, будет медленным. Кроме того, это излишне, так как таким приложениям не нужны криптографически безопасные случайные числа. Вместо этого используйте интерфейсы, описанные на этой странице, чтобы получить небольшое количество данных для запуска генератора псевдослучайных чисел в пространстве пользователя, который будет задействован для таких приложений.

### Сравнение getrandom, /dev/urandom и /dev/random
В следующую таблицу сведено поведение различных интерфейсов получения случайных чисел. Флаг GRND_NONBLOCK можно использовать для управления поведением блокирования getrandom(2). В последней колонке таблицы показано, что может произойти на ранней стадии загрузки ОС, когда пул энтропии ещё не инициализирован.

Интерфейс

Пул

Возникновение блокировки

Поведение, когда пул ещё не готов

/dev/random

Блокирующий пул

Если энтропии недостаточно, то блокирует до тех пор, пока не наберётся нужно количество энтропии

Блокирует, пока не наберётся нужно количество энтропии

/dev/urandom

Данные CSPRNG

Никогда не блокируется

Возвращает данные из неинициализированного CSPRNG (может быть низкая энтропия и не подходить для шифрования)

getrandom()

Тоже, что и /dev/urandom

Не блокирует в ожидании пула

Блокирует до готовности пула

getrandom() GRND_RANDOM

Тоже, что и /dev/random

Если энтропии недостаточно, то блокирует до тех пор, пока не наберётся нужно количество энтропии

Блокирует до готовности пула

getrandom() GRND_NONBLOCK

Тоже, что и /dev/urandom

Не блокирует в ожидании пула

EAGAIN

getrandom() GRND_RANDOM + GRND_NONBLOCK

Тоже, что и /dev/random

EAGAIN, если недостаточно энтропии

EAGAIN

### Генерация ключей шифрования
Количество начального материала, требуемое для генерации ключей шифрования, равно эффективному размеру ключа. Например, 307 2-битный закрытый ключ RSA или Diffie-Hellman имеет эффективный размер ключа бит (для его подбора требуется просмотреть 2^128 значений), поэтому генератору ключа нужно только 128 бит (16 байт) начального материала из /dev/random.

Так как разумно добавить некоторый запас прочности к выше указанному минимуму как защиту против недостатков в алгоритме CSPRNG, никакой доступный криптографический примитив сегодня не может обещать больше чем 256 бит безопасности, поэтому если какая-то программа читает больше чем 256 бит (32 байта) из пула случайных чисел ядра за вызов, или за разумный интервал повторного посева (не менее одной минуты), то это нужно считать признаком того, что шифрование в ней реализовано НЕДОСТАТОЧНО продуманно.

## СМОТРИТЕ ТАКЖЕ
getrandom(2), getauxval(3), getentropy(3), random(4), urandom(4), signal(7)

branch: sisyphus


raw

title: raw(7)

summary: неструктурированные сокеты IPv4 в Linux

text:
# raw(7)

## ИМЯ
raw - неструктурированные сокеты IPv4 в Linux

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

\#include <netinet/in.h>

raw_socket = socket(AF_INET, SOCK_RAW, int protocol);

## ОПИСАНИЕ
Неструктурированные (raw) сокеты позволяют реализовать новые протоколы IPv4 в пространстве пользователя. Через неструктурированный сокет получают или посылают необработанные датаграммы, не включающие в себя заголовки уровня соединения (link level).

Уровень IPv4 генерирует заголовок IP при посылке пакета, если только для сокета не включён параметр IP_HDRINCL. Если он включён, то пакет должен содержать заголовок IP. Принимаемые пакеты всегда содержат заголовок IP.

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

Все пакеты или ошибки, совпадающие с номером протокола protocol, указанным неструктурированному сокету, передаются этому сокету. Список допустимых протоколов назначается списком IANA http://www.iana.org/assignments/protocol-numbers/ и содержится в getprotobyname(3).

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

Поля заголовка IP, изменяемые IP_HDRINCL при передаче

контрольная сумма IP

всегда заполняется

адрес источника

заполняется, если значение равно нулю

ID пакета

заполняется, если значение равно нулю

общая длина

всегда заполняется

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

Если IP_HDRINCL не указан, то параметры заголовка IP в неструктурированных сокетах могут быть установлены с помощью setsockopt(2); более подробная информация приведена в ip(7).

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

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

### Формат адреса
При отправке и приёме дейтаграмм (sendto(2), recvfrom(2) и similar) через неструктурированные сокеты используется стандартная адресная структура sockaddr_in, определённая в ip(7). Поле sin_port можно использовать для указания номера протокола IP, но в Linux 2.2 и новее оно игнорируется при отправке, и должно всегда равняться 0 (смотрите ДЕФЕКТЫ). У входящих пакетов sin_port равен нулю.

### Параметры сокета
Параметры неструктурированных сокетов могут быть установлены с помощью setsockopt(2) и прочитаны с помощью getsockopt(2) с указанием флага семейства IPPROTO_RAW.

ICMP_FILTER

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

Кроме этого, поддерживаются все датаграммные параметры сокетов ip(7) для IPPROTO_IP.

### Обработка ошибок
Ошибки, возникающие в сети, передаются пользователю только, если сокет подключён или установлен флаг IP_RECVERR. В целях совместимости в подключенные сокеты передаются только EMSGSIZE и EPROTO. При указании IP_RECVERR в очереди ошибок сохраняются все сетевые ошибки.

## ОШИБКИ
EACCES

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

EFAULT

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

EINVAL

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

EMSGSIZE

Размер пакета слишком велик, либо включён Path MTU Discovery (флаг сокета IP_PMTU_DISCOVER), либо размер пакета превышает максимально разрешенный для IPv4 размер, равный 64 КБ.

EOPNOTSUPP

Сокетному вызову был передан неверный флаг (например, MSG_OOB).

EPERM

Пользователь не имеет прав на открытие неструктурированных сокетов. Это могут делать только процессы с идентификатором эффективного пользователя равным 0, или имеющие мандат CAP_NET_RAW.

EPROTO

Получена ошибка ICMP, сообщающая о проблеме с параметром.

## ВЕРСИИ
Значения IP_RECVERR и ICMP_FILTER появились в Linux 2.2. Они являются расширениями Linux и не должны использоваться в переносимых программах.

Код неструктурированных сокетов в версии Linux 2.0 при установленном параметре SO_BSDCOMPAT был специально сделан совместимым с BSD «вплоть до ошибок». Из Linux 2.2 это было удалено.

## ЗАМЕЧАНИЯ
По умолчанию, для неструктурированных сокетов выполняется обнаружение MTU (Maximum Transmission Unit) пути. Это означает, что ядро будет следить за MTU до IP-адреса назначения и возвращать EMSGSIZE, если запись неструктурированного пакета превысит это значение. Когда это происходит, приложение должно уменьшить размер пакета. Также обнаружение MTU пути можно выключить с помощью параметра сокета IP_MTU_DISCOVER или в файле /proc/sys/net/ipv4/ip_no_pmtu_disc; подробней смотрите в ip(7). При отключении обнаружения неструктурированные сокеты фрагментируют исходящие пакеты, размер которых превышает MTU интерфейса. Однако по соображениям производительности и надёжности отключение не рекомендуется.

Неструктурированный сокет может быть подключён к определённому локальному адресу с помощью вызова bind(2). Если он не подключён, то принимаются все пакеты указанного протокола IP. Кроме того, неструктурированный сокет может быть подключён к определённому сетевому устройству с помощью SO_BINDTODEVICE; смотрите socket(7).

Сокет IPPROTO_RAW предназначен только для отправки. Если вы хотите получать все пакеты IP, используйте сокет packet(7) с протоколом ETH_P_IP. Заметим, что пакетные сокеты, в отличие от неструктурированных сокетов, не собирают пакеты из фрагментов IP.

Если вы хотите получать все пакеты ICMP для датаграммного сокета, то лучше использовать IP_RECVERR на определённом сокете; смотрите ip(7).

Неструктурированные сокеты могут перехватывать в Linux все протоколы IP, даже имеющие протокольный модуль в ядре (такие, как ICMP или TCP). В этом случае пакеты передаются как модулю ядра, так и неструктурированным сокетам. На это нельзя закладываться в переносимых программах, так как многие другие реализации сокетов BSD так не делают.

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

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

Передача через неструктурированный сокет должна осуществляться с помощью протокола IP из sin_port; эта возможность исчезла в Linux 2.2. Метод обхода — использовать IP_HDRINCL.

## ДЕФЕКТЫ
Не описаны расширения прозрачного прокси.

Если установлен параметр IP_HDRINCL, датаграммы не будут фрагментированы и их размер будет ограничен MTU интерфейса.

В Linux 2.2 отсутствует настройка протокола IP для отправки sin_port — всегда используется тот протокол, к которому был подключён сокет или который был указан при первом вызове socket(2).

## СМОТРИТЕ ТАКЖЕ
recvmsg(2), sendmsg(2), capabilities(7), ip(7), socket(7)

В RFC 1191 описан процесс обнаружения маршрута MTU. В RFC 791 и заголовочном файле <linux/ip.h> описан протокол IP.


regex

title: regex(7)

summary: регулярные выражения POSIX.2

text:
# regex(7)

## ИМЯ
regex - регулярные выражения POSIX.2

## ОПИСАНИЕ
Регулярные выражения (РВ) стандарта POSIX.2 могут быть двух видов: новые РВ (по сути, использующиеся в egrep; в POSIX.2 их называют ещё «расширенными» РВ) и устаревшие РВ (по сути, использующиеся в ed(1); в POSIX.2 их называют ещё «основными» РВ). Устаревшие РВ существуют, в основном, для совместимости с некоторыми старыми программами (они будут подробнее рассмотрены в конце этого документа). В POSIX.2 не разъяснены некоторые вопросы синтаксиса РВ; знаком (!) отмечаются описания, которые могут быть не полностью совместимы с другими реализациями POSIX.2.

Новое РВ — одна(!) или более непустых(!) ветвей, разделённых '|'. Соответствием считается, если есть совпадение для любой из её ветвей.

Ветвь состоит из одной(!) или более частей. Ветвь сначала ведёт поиск соответствий с первой, затем с второй (и т. п.) её частями.

Часть — это атом, за которым может следовать одиночный(!) символ '*', '+', '?' или интервал. Если за атомом следует символ '*', это означает, что совпадающая с атомом последовательность может встречаться 0 или более раз. Если за атомом следует символ '+', это означает, что совпадающая с атомом последовательность может встречаться 1 или более раз. Если за атомом следует символ '?', это означает, что совпадающая с атомом последовательность может встречаться 0 или 1 раз.

Интервал — это символ '{', после которого стоит беззнаковое целое десятичное число, за которым может следовать символ ',', далее, возможно, находится ещё одно беззнаковое целое десятичное число, и в конце интервала обязательно стоит символ '}'. Числа должны находиться в промежутке от 0 до RE_DUP_MAX (255(!)) включительно, а если указано два числа, то первое не должно превышать второе. Атом с интервалом, в котором есть одно число i и нет запятой, соответствует последовательности, повторяющейся точно i раз. Атом с интервалом, содержащим число i и запятую, соответствует последовательности, повторяющейся i и более раз. Атом с интервалом, содержащим два числа i и j, соответствует последовательности, повторяющейся от i до j раз включительно.

Атом — это регулярное выражение, заключённое в «()» (соответствующее регулярному выражению), пустые скобки «()» (соответствуют строке null)(!), выражение в квадратных скобках (см. ниже), '.' (соответствует любому одному символу), '^' (соответствует строке null в начале строки), '$' (соответствует строке null в конце строки), '\' со следующим после него одним из символов «^.[$()|*+?{\» (соответствует этому символу, как он есть), символ '\' с последующим символом, отличным от предыдущего(!) (соответствует этому символу, как он есть, как если бы '\' отсутствовал(!)), или одиночный символ без специального назначения (соответствует этому символу). Символ '{' с последующим символом, не являющимся цифрой, соответствует символу, а не началу интервала(!). Нельзя заканчивать РВ символом '\'.

Выражение в квадратных скобках — список символов, заключенный в «[]». Обычно, оно соответствует любому отдельному символу из списка (но см. ниже). Если список начинается с '^', то он соответствует любому отдельному символу (но см. ниже) не из приведённого списка. Если два символа в списке разделены '-', то это считается сокращением полного диапазона символов, заключённого между этими двумя символами (включая и их) объединяющей последовательности, например, «[0-9]» в кодах ASCII соответствует любой десятичной цифре. Нельзя(!) в двух диапазонах указывать один и тот же символ, например, «a-c-e». Диапазоны сильно зависят от объединяющей последовательности, и в переносимых программах их лучше не использовать.

Для того, чтобы включить в список символ ']', вам следует поставить его в начало списка (после символа '^', если он присутствует). Для того, чтобы включить в список символ '-', поставьте его первым или последним символом или вторым символом конца диапазона. Для того, чтобы обозначить символом '-' начало диапазона, заключите его в «[.» и «.]», сделав его объединяющим элементом (смотрите далее). За исключением этих и некоторых других комбинаций, использующих '[' (см. следующие параграфы), все остальные специальные символы, включая '\', теряют своё особое назначение в квадратных скобках.

Если внутри квадратных скобок объединяющий элемент (одиночный символ, многосимвольная последовательность, которая действует как одиночный символ или имя объединяющей последовательности) заключен в «[.» и «.]», то он обозначает последовательность символов как один объединяющий элемент. Последовательность выражается одиночным элементом списка внутри квадратных скобок. Таким образом, выражение в скобках, содержащее многосимвольный объединяющий элемент, может соответствовать более чем одному символу; например, если последовательность содержит объединяющий элемент «ch», то РВ «[[.ch.]]*c» соответствует первым пяти символам «chchcc».

Объединяющий элемент в квадратных скобках, заключенный в «[=» и «=]» — это класс-эквивалент, делающий последовательности символов всех объединяющих элементов эквивалентными одной, включая её саму (если нет больше эквивалентных объединяющих элементов, то это аналогично выражению, заключенному в «[.» и «.]»). Например, если o и ^ являются членами класса-эквивалента, то «[[=o=]]», «[[=^=]]» и «[o^]» являются синонимами. Класс-эквивалент не(!) может служить границей диапазона.

В выражении в квадратных скобках, имя символьного класса, заключенное в «[:» и «:]», соответствует списку всех символов, принадлежащих этому классу. Существуют стандартные символьные классы:

alnum

digit

punct

alpha

graph

space

blank

lower

upper

cntrl

print

xdigit

Эти символьные классы определены в wctype(3). В локали могут быть определены свои классы. Символьный класс не может использоваться в качестве границы диапазона.

В случае, если РВ совпадает более чем с одной подстрокой заданной строки, то оно считается совпадающим с первой подстрокой строки. Если РВ совпадает более чем с одной подстрокой начинающейся в этой точке, то оно совпадет с самой длинной подстрокой. Подвыражения также соответствуют самой длинной совпадающей подстроке, полное соответствие должно быть наиболее длинным, и подвыражения, стоящие в РВ первыми, имеют приоритет над остальными, находящимися далее. Заметим, что высокоуровневые подвыражения имеют приоритет над низкоуровневыми компонентами подвыражений.

Длина совпадений измеряется в символах, а не в объединяющих элементах. Строка null считается длиннее чем не имеющая совпадений. Например, «bb*» совпадает с тремя средними символами «abbbc», «(wee|week)(knights|nights)» совпадает со всеми десятью символами «weeknights», а когда «(.*).*» сравнивается с «abc», подвыражение в скобках совпадает со всеми тремя символами; при сравнении «(a*)*» с «bc» получается, что РВ и подвыражение в скобках соответствуют строке null.

Если указано учитывать совпадение независимо от регистра, то все различия по регистру удаляются из алфавита. Когда буква присутствует в различных регистрах вне квадратных скобок, то она трансформируется в выражение в квадратных скобках, содержащее оба регистра, например, 'x' становится «[xX]». Если буква уже заключена в скобки, то к ней добавляется и другой регистр, например, «[x]» становится «[xX]» , а «[^x]» превращается в «[^xX]».

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

Устаревшие («основные») РВ отличаются по нескольким аспектам. Символы '|', '+' и '?' считаются обычными символами. Для обозначения границ интервалов используются «\{» и «\}», а '{' и '}' сами по себе являются обычными символами. Для обособления подвыражений используются «\(» и «\)», а '(' и ')' сами по себе являются обычными символами. Символ '^' является обычным символом за исключением того случая, когда он стоит в начале РВ или(!) в начале подвыражения в круглых скобках; символ '$' является обычным символом, кроме того случая, когда он стоит в конце РВ или(!) в конце подвыражения в круглых скобках; символ '*' является обычным, если он стоит в начале РВ или в начале подвыражения в круглых скобках (возможно, после символа '^' в самом начале).

Кроме этого, существует ещё один тип атома — обратная ссылка: '\' с последующей за ней ненулевой десятичной цифрой d соответствует той самой последовательности, что и d-е подвыражение в скобках (нумерация подвыражений считается по их открывающим круглым скобкам, слева направо). Пример: «\([bc]\)\1» соответствует «bb» или «cc», но не «bc».

## ДЕФЕКТЫ
Наличие двух видов РВ — вынужденная мера.

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

Обратные ссылки — также вынужденная мера, вызывают серьёзные проблемы эффективности в реализациях. Также они не имеют подробного определения (например, «a\(\(b\)*\2\)*d» соответствует «abbbd»?).

Определение в POSIX.2 совпадения при отключении учёта регистра тоже очень туманное. Определение типа «один регистр замещает все остальные», по мнению некоторых специалистов, не является правильным.

## АВТОР
Эта страница взята из пакета regex, написанного Генри Спенсером (Henry Spencer).

## СМОТРИТЕ ТАКЖЕ
grep(1), regex(3)

POSIX.2, раздел 2.8 (запись регулярных выражений).


rtld-audit

title: rtld-audit(7)

text:
# rtld-audit(7)

## ИМЯ
rtld-audit - программный интерфейс слежения за динамическим компоновщиком

## ОБЗОР

```
#define _GNU_SOURCE             /* смотрите feature_test_macros(7) */
#include <link.h>
```

## ОПИСАНИЕ
Динамический компоновщик GNU (компоновщик времени выполнения) предоставляет API слежения, который позволяет приложению получать уведомления о различных событиях динамической компоновки. Данный API очень похож на интерфейс слежения, предоставляемый компоновщиком времени выполнения из Solaris. Необходимые константы и прототипы определены в <link.h>.

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

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

### la_version()

```
unsigned int la_version(unsigned int version);
```

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

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

### la_objsearch()

```
char *la_objsearch(const char *name, uintptr_t *cookie,
                   unsigned int flag);
```

Динамический компоновщик вызывает эту функцию для информирования отслеживающей библиотеки при поиске общего объекта. Аргумент name содержит имя файла или путь, который будет разыскиваться. В cookie указывается общий объект, который начал поиск. Аргумент flag устанавливается в одно из следующих значений:

LA_SER_ORIG

Это оригинальное имя, которое будет разыскиваться. Как правило, это имя хранится в записи ELF DT_NEEDED или был передан в аргументе filename при вызове dlopen(3).

LA_SER_LIBPATH

Значение name было создано с использованием каталога из LD_LIBRARY_PATH.

LA_SER_RUNPATH

Значение name было создано с использованием каталога из списка ELF DT_RPATH или DT_RUNPATH.

LA_SER_CONFIG

Значение name было найдено в кэше ldconfig(8) (/etc/ld.so.cache).

LA_SER_DEFAULT

Значение name было найдено при поиске в одном из каталогов по умолчанию.

LA_SER_SECURE

Значение name относится к объекту безопасности (не используется в Linux).

Функция la_objsearch() возвращает путь, который динамический компоновщик должен использовать в дальнейшей работе. Если возвращается NULL, то путь игнорируется в дальнейшей работе. Если данная отслеживающая библиотека создана для простого слежения за путями поиска, то должно возвращаться name.

### la_activity()

```
void la_activity( uintptr_t *cookie, unsigned int flag);
```

Динамический компоновщик вызывает эту функцию для информирования библиотеки слежения о выполнении действия с картой ссылок (link-map). В cookie задаётся объект, находящийся в начале карты ссылок. Когда динамический компоновщик вызывает эту функцию, аргумент flag устанавливается в одно из следующих значений:

LA_ACT_ADD

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

LA_ACT_DELETE

Из карты ссылок удаляется объект.

LA_ACT_CONSISTENT

Действие с картой ссылок завершено: карта снова корректна (consistent).

### la_objopen()

```
unsigned int la_objopen(struct link_map *map, Lmid_t lmid,
                        uintptr_t *cookie);
```

Динамический компоновщик вызывает эту функцию при загрузке нового общего объекта. Аргумент map является указателем на структуру карты ссылок (link-map), которая описывает объект. Поле lmid устанавливается в одно из следующих значений:

LM_ID_BASE

Карта ссылок является частью начального пространства имён (namespace).

LM_ID_NEWLM

Карта ссылок является частью нового пространства имён, запрошенного через dlmopen(3).

Аргумент cookie — указатель на идентификатор этого объекта. Идентификатор используется при последующих вызовах функций отслеживающей библиотеки для идентификации этого объекта. Данный идентификатор инициализируется указателем на карту ссылок объекта, но отслеживающая библиотека может изменить идентификатор на другое значение, которое ей удобней использовать для обращения к объекту.

Функция la_objopen() возвращает битовую маску, созданное с помощью сложения (OR) нуля или более следующих констант, которые позволяют отслеживающей библиотеке выбирать наблюдаемые объекты через la_symbind*():

LA_FLG_BINDTO

Следить за символьными привязками этого объекта.

LA_FLG_BINDFROM

Следить за символьными привязками из этого объекта.

Возвращаемое значение 0 из la_objopen() указывает на то, что не нужно отслеживать символьные привязки этого объекта.

### la_objclose()

```
unsigned int la_objclose(uintptr_t *cookie);
```

Динамический компоновщик вызывает эту функцию после выполнения конечного кода (finalization code), но до выгрузки объекта. В cookie задаётся идентификатор, полученный ранее из вызова la_objopen().

В текущей реализации значение, возвращаемое la_objclose(), игнорируется.

### la_preinit()

```
void la_preinit(uintptr_t *cookie);
```

Динамический компоновщик вызывает эту функцию после загрузки всех общих объектов, но до передачи управления приложению (то есть, до вызова main()). Заметим, что main() позднее всё ещё может динамически загрузить объекты с помощью dlopen(3).

### la_symbind*()

```
uintptr_t la_symbind32(Elf32_Sym *sym, unsigned int ndx,
                       uintptr_t *refcook, uintptr_t *defcook,
                       unsigned int *flags, const char *symname);
uintptr_t la_symbind64(Elf64_Sym *sym, unsigned int ndx,
                       uintptr_t *refcook, uintptr_t *defcook,
                       unsigned int *flags, const char *symname);
```

Динамический компоновщик вызывает одну из этих функций при выполнении символьной привязки между двумя общими объектами, которые были помечены для уведомления функцией la_objopen(). Функция la_symbind32() применяется на 32-битных платформах; la_symbind64() применяется на 64-битных платформах.

Аргумент sym является указателем на структуру, которая содержит информацию о привязываемом символе. Определение структуры находится в <elf.h>. Среди полей структуры есть поле st_value, которое содержит адрес привязываемого символа.

В аргументе ndx указывается индекс символа в таблице символов привязываемого общего объекта.

В аргументе refcook указывается общий объект, который ссылается на символ; это тот же идентификатор, который указывается в функции la_objopen(), возвращающей LA_FLG_BINDFROM. В аргументе defcook указывается общий объект, который определяет символ, на который производится ссылка; это тот же идентификатор, который указывается в функции la_objopen(), возвращающей LA_FLG_BINDTO.

В аргументе symname задаётся строка, содержащая имя символа.

Аргумент flags представляет собой битовую маску, которая содержит информацию о символе и может использоваться для изменения дальнейшего отслеживания этой записи PLT (Procedure Linkage Table). Динамический компоновщик может передавать следующие битовые значения в этом аргументе:

LA_SYMB_DLSYM

Привязка возникла из-за вызова dlsym(3).

LA_SYMB_ALTVALUE

Предыдущий вызов la_symbind*() вернул альтернативное значение для этого символа.

По умолчанию, если в отслеживающей библиотеке реализованы функции la_pltenter() и la_pltexit() (смотрите ниже), то эти функции вызываются после la_symbind() для записей PLT каждый раз при ссылке на символ. Следующие флаги могут объединяться с помощью OR в *flags для изменения данного поведения по умолчанию:

LA_SYMB_NOPLTENTER

Не вызывать la_pltenter() для этого символа.

LA_SYMB_NOPLTEXIT

Не вызывать la_pltexit() для этого символа.

Возвращаемое значение la_symbind32() и la_symbind64() представляет собой адрес, по которому нужно передать управление после возврата функций. Если отслеживающая библиотека просто наблюдает за привязкой символов, то должно возвращаться sym->st_value. Может возвращаться другое значение, если библиотека хочет передать управление в другое место.

### la_pltenter()
Точное имя и типы аргументов данной функции зависят от аппаратной платформы (подходящее определение приведено в <link.h>). Ниже показано определение для x86-32:

```
Elf32_Addr la_i86_gnu_pltenter(Elf32_Sym *sym, unsigned int ndx,
                 uintptr_t *refcook, uintptr_t *defcook,
                 La_i86_regs *regs, unsigned int *flags,
                 const char *symname, long int *framesizep);
```

Эта функция вызывается до вызова записи PLT между двумя общими объектами, которые помечены для уведомления о привязке.

Значение аргументов sym, ndx, refcook, defcook и symname такое же как у la_symbind*().

Аргумент regs указывает на структуру (определена в <link.h>), содержащую значения регистров, которые будут использованы для вызова этой записи PLT.

Аргумент flags указывает на битовую маску, которая сообщает информацию и может использоваться для изменения последующего слежения за этой записью PLT; значения как у la_symbind*().

Аргумент framesizep указывает на буфер long int, который можно использовать для явного определения размера фрейма, используемого для вызова этой записи PLT. Если другие вызовы la_pltenter() для этого символа возвращают другие значения, то используется максимальное полученное значение. Функция la_pltexit() вызывается только, если этот буфер явно устанавливает подходящее значение.

Возвращаемое la_pltenter() значение подобно la_symbind*().

### la_pltexit()
Точное имя и типы аргументов данной функции зависят от аппаратной платформы (подходящее определение приведено в <link.h>). Ниже показано определение для x86-32:

```
unsigned int la_i86_gnu_pltexit(Elf32_Sym *sym, unsigned int ndx,
                 uintptr_t *refcook, uintptr_t *defcook,
                 const La_i86_regs *inregs, La_i86_retval *outregs,
                 const char *symname);
```

Эта функция вызывается после завершения вызова записи PLT, выполняемой между двумя общими объектами, которые были помечены для уведомления при привязке. Функция вызывается перед передачей управления из записи PLT вызывающему.

Значение аргументов sym, ndx, refcook, defcook и symname такое же как у la_symbind*().

Аргумент inregs указывает на структуру (определена в <link.h>), содержащую значения регистров, используемых для вызова этой записи PLT. Аргумент outregs указывает на структуру (определена в <link.h>), содержащую значения для вызова в эту запись PLT. Эти значения могут изменяться вызывающим и изменения будут видимы вызывающему запись PLT.

В текущей реализации GNU возвращаемое значение la_pltexit() игнорируется.

## СООТВЕТСТВИЕ СТАНДАРТАМ
Данный API не стандартен, но очень похож на Solaris API, описанный в Solaris Linker and Libraries Guide в главе Runtime Linker Auditing Interface.

## ЗАМЕЧАНИЯ
Отметим следующие отличия API динамического компоновщика в Solaris:

- Интерфейс Solaris la_objfilter() не поддерживается в реализации GNU.

- В функциях Solaris la_symbind32() и la_pltexit() нет аргумента symname.

- В функции Solaris la_pltexit() нет аргументов inregs и outregs (но есть аргумент retval со значением, возвращаемым функцией).

## ДЕФЕКТЫ
В glibc до версии 2.9 включительно, указание более одной отслеживающей библиотеки в LD_AUDIT приводит к падению во время выполнения. Это исправлено в glibc 2.10.

## ПРИМЕР

```
#include <link.h>
#include <stdio.h>
unsigned int
la_version(unsigned int version)
{

    printf("la_version(): %d\n", version);

    return version;
}
char *
la_objsearch(const char *name, uintptr_t *cookie, unsigned int flag)
{

    printf("la_objsearch(): name = %s; cookie = %p", name, cookie);

    printf("; flag = %s\n",

            (flag == LA_SER_ORIG) ?    "LA_SER_ORIG" :

            (flag == LA_SER_LIBPATH) ? "LA_SER_LIBPATH" :

            (flag == LA_SER_RUNPATH) ? "LA_SER_RUNPATH" :

            (flag == LA_SER_DEFAULT) ? "LA_SER_DEFAULT" :

            (flag == LA_SER_CONFIG) ?  "LA_SER_CONFIG" :

            (flag == LA_SER_SECURE) ?  "LA_SER_SECURE" :

            "???");

    return name;
}
void
la_activity (uintptr_t *cookie, unsigned int flag)
{

    printf("la_activity(): cookie = %p; flag = %s\n", cookie,

            (flag == LA_ACT_CONSISTENT) ? "LA_ACT_CONSISTENT" :

            (flag == LA_ACT_ADD) ?        "LA_ACT_ADD" :

            (flag == LA_ACT_DELETE) ?     "LA_ACT_DELETE" :

            "???");
}
unsigned int
la_objopen(struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
{

    printf("la_objopen(): loading \"%s\"; lmid = %s; cookie=%p\n",

            map->l_name,

            (lmid == LM_ID_BASE) ?  "LM_ID_BASE" :

            (lmid == LM_ID_NEWLM) ? "LM_ID_NEWLM" :

            "???",

            cookie);

    return LA_FLG_BINDTO | LA_FLG_BINDFROM;
}
unsigned int
la_objclose (uintptr_t *cookie)
{

    printf("la_objclose(): %p\n", cookie);

    return 0;
}
void
la_preinit(uintptr_t *cookie)
{

    printf("la_preinit(): %p\n", cookie);
}
uintptr_t
la_symbind32(Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,

        uintptr_t *defcook, unsigned int *flags, const char *symname)
{

    printf("la_symbind32(): symname = %s; sym->st_value = %p\n",

            symname, sym->st_value);

    printf("        ndx = %d; flags = 0x%x", ndx, *flags);

    printf("; refcook = %p; defcook = %p\n", refcook, defcook);

    return sym->st_value;
}
uintptr_t
la_symbind64(Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,

        uintptr_t *defcook, unsigned int *flags, const char *symname)
{

    printf("la_symbind64(): symname = %s; sym->st_value = %p\n",

            symname, sym->st_value);

    printf("        ndx = %d; flags = 0x%x", ndx, *flags);

    printf("; refcook = %p; defcook = %p\n", refcook, defcook);

    return sym->st_value;
}
Elf32_Addr
la_i86_gnu_pltenter(Elf32_Sym *sym, unsigned int ndx,

        uintptr_t *refcook, uintptr_t *defcook, La_i86_regs *regs,

        unsigned int *flags, const char *symname, long int *framesizep)
{

    printf("la_i86_gnu_pltenter(): %s (%p)\n", symname, sym->st_value);

    return sym->st_value;
}
```

## СМОТРИТЕ ТАКЖЕ
ldd(1), dlopen(3), ld.so(8), ldconfig(8)


rtnetlink

title: rtnetlink(7)

summary: сокет маршрутизации IPv4 в Linux

text:
# rtnetlink(7)

## ИМЯ
rtnetlink - сокет маршрутизации IPv4 в Linux

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

\#include <linux/netlink.h>

\#include <linux/rtnetlink.h>

\#include <sys/socket.h>

rtnetlink_socket = socket(AF_NETLINK, int socket_type, NETLINK_ROUTE);

## ОПИСАНИЕ
Rtnetlink позволяет читать и изменять таблицы маршрутизации ядра. Он используется для взаимодействия различных подсистем внутри ядра (это здесь не описано), а также для взаимодействия пользовательских программ. Сетевыми маршрутами, IP-адресами, параметрами связи (link parameters), настройками соседства (neighbor setups), алгоритмами планирования очереди (queueing disciplines), классификацией трафика и и пакетными классификаторами можно управлять через сокеты NETLINK_ROUTE. Они основываются на сообщениях netlink; подробности смотрите в netlink(7).

### Атрибуты маршрутизации
Некоторые сообщения rtnetlink содержат необязательные атрибуты после начального заголовка:

```
struct rtattr {

    unsigned short rta_len;    /* длина параметра */

    unsigned short rta_type;   /* тип параметра */

    /* данные … */
};
```

Этими атрибутами нужно управлять только с помощью макросов RTA_* или libnetlink, смотрите rtnetlink(3).

### Сообщения
Rtnetlink поддерживает следующие типы сообщений (в дополнении к стандартным сообщениям netlink):

RTM_NEWLINK, RTM_DELLINK, RTM_GETLINK

Создание, удаление и получение информации об определённом сетевом интерфейсе. Эти сообщения содержат структуру ifinfomsg, за которой следует ряд структур rtattr.

```
struct ifinfomsg {

    unsigned char  ifi_family; /* AF_UNSPEC */

    unsigned short ifi_type;   /* тип устройства */

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

    unsigned int   ifi_flags;  /* флаги устройства */

    unsigned int   ifi_change; /* маска изменения */
};

```

В ifi_flags содержатся флаги устройства, смотрите netdevice(7); в ifi_index — уникальный индекс интерфейса (начиная с Linux 3.7 возможно передать ненулевое значение в сообщении RTM_NEWLINK; в этом случае создаётся связь (link) с заданным ifindex); элемент ifi_change зарезервирован на будущее и его значение всегда должно быть равно 0xFFFFFFFF. Атрибуты маршрутизации

rta_type

тип значения

описание

IFLA_UNSPEC

-

не определено

IFLA_ADDRESS

аппаратный адрес

адрес интерфейса L2

IFLA_BROADCAST

аппаратный адрес

широковещательный адрес L2

IFLA_IFNAME

строка asciiz

имя устройства

IFLA_MTU

unsigned int

MTU устройства

IFLA_LINK

int

тип связи

IFLA_QDISC

строка asciiz

алгоритм очереди

IFLA_STATS

смотрите ниже

статистика интерфейса

Тип значения для IFLA_STATS — struct rtnl_link_stats (в Linux 2.4 и старее — struct net_device_stats).

RTM_NEWADDR, RTM_DELADDR, RTM_GETADDR

Добавление, удаление или получение информации об IP-адресе, назначенном интерфейсу. В Linux 2.2 интерфейс может иметь несколько IP-адресов; эта концепция пришла на смену псевдонимам устройства, использовавшимся в версии 2.0. В Linux 2.2 эти сообщения поддерживают адреса IPv4 и IPv6. В них содержится структура ifaddrmsg, которая может быть указана после атрибутов маршрутизации rtattr.

```
struct ifaddrmsg {

    unsigned char ifa_family;    /* тип адреса */

    unsigned char ifa_prefixlen; /* длина префикса адреса */

    unsigned char ifa_flags;     /* флаги адреса */

    unsigned char ifa_scope;     /* область адреса */

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

```

Поле ifa_family представляет тип адресного семейства (AF_INET или AF_INET6), ifa_prefixlen — длину адресной маски адреса, если это применимо для семейства (в IPv4), ifa_scope — область адреса, ifa_index — индекс интерфейса, которому назначен адрес. Поле ifa_flags — слово флагов: IFA_F_SECONDARY — вторичный адрес (старый псевдоним интерфейса), IFA_F_PERMANENT — постоянный адрес, назначенный пользователем и другие недокументированные флаги. Атрибуты

rta_type

тип значения

описание

IFA_UNSPEC

-

не определено

IFA_ADDRESS

адрес неструктурированного протокола

адрес интерфейса

IFA_LOCAL

адрес неструктурированного протокола

локальный адрес

IFA_LABEL

строка asciiz

название интерфейса

IFA_BROADCAST

адрес неструктурированного протокола

широковещательный адрес

IFA_ANYCAST

адрес неструктурированного протокола

адрес anycast

IFA_CACHEINFO

struct ifa_cacheinfo

информация об адресе

RTM_NEWROUTE, RTM_DELROUTE, RTM_GETROUTE

Создание, удаление или получение информации о сетевом маршруте. Эти сообщения содержат структуру rtmsg с необязательными дополнительными структурами rtattr. Для RTM_GETROUTE, если rtm_dst_len и rtm_src_len задать значение 0, то вы получите все записи определённой таблицы маршрутизации. В других полях, кроме rtm_table и rtm_protocol, 0 считается шаблоном (wildcard).

```
struct rtmsg {

    unsigned char rtm_family;   /* адресное семейство маршрута */

    unsigned char rtm_dst_len;  /* длина назначения */

    unsigned char rtm_src_len;  /* длина источника */

    unsigned char rtm_tos;      /* фильтр TOS */

    unsigned char rtm_table;    /* ID таблицы маршрутизации */

    unsigned char rtm_protocol; /* протокол марш-ции; см. ниже */

    unsigned char rtm_scope;    /* см. ниже */

    unsigned char rtm_type;     /* см. ниже */

    unsigned int  rtm_flags;
};

```

rtm_type

Тип маршрута

RTN_UNSPEC

неизвестный маршрут

RTN_UNICAST

шлюз или прямой маршрут

RTN_LOCAL

маршрут локального интерфейса

RTN_BROADCAST

локальный широковещательный маршрут (широковещательная отправка)

RTN_ANYCAST

локальный широковещательный маршрут (однонаправленная отправка)

RTN_MULTICAST

многоадресный маршрут

RTN_BLACKHOLE

маршрут для отброса пакетов

RTN_UNREACHABLE

недостижимый пункт назначения

RTN_PROHIBIT

маршрут для отклонения пакетов

RTN_THROW

продолжение поиска маршрута в другой таблице

RTN_NAT

правило трансляции сетевого адреса

RTN_XRESOLVE

ссылка на внешний определитель (не реализовано)

Происхождение маршрута

RTPROT_UNSPEC

неизвестно

RTPROT_REDIRECT

из-за перенаправления полученном по ICMP (не используется)

RTPROT_KERNEL

посылается ядром

RTPROT_BOOT

при загрузке машины

RTPROT_STATIC

указан администратором

Значения больше RTPROT_STATIC не учитываются ядром, они предназначены только для пользовательской информации. Они могут использоваться для пометки источника информации о маршрутизации или для отличения различных служб маршрутизации друг от друга. Уже назначенные идентификаторы для служб маршрутизации можно найти в <linux/rtnetlink.h>.

rtm_scope — расстояние до назначения: RT_SCOPE_UNIVERSE

глобальный маршрут

RT_SCOPE_SITE

внутренний маршрут в локальной автономной системе

RT_SCOPE_LINK

маршрут на эту связь

RT_SCOPE_HOST

маршрут на локальный узел

RT_SCOPE_NOWHERE

назначение не существует

Значения от RT_SCOPE_UNIVERSE и до RT_SCOPE_SITE доступны пользователю.

Поле rtm_flags может иметь следующие значения: RTM_F_NOTIFY

если маршрут изменился — уведомить пользователя через rtnetlink

RTM_F_CLONED

маршрут склонирован из другого маршрута

RTM_F_EQUALIZE

многопутевой уравниватель (не реализовано)

В rtm_table задаётся таблица маршрутизации:

RT_TABLE_UNSPEC

таблица маршрутизации не задана

RT_TABLE_DEFAULT

таблица по умолчанию

RT_TABLE_MAIN

главная таблица

RT_TABLE_LOCAL

локальная таблица

Пользователь может назначать произвольные значения от RT_TABLE_UNSPEC и до RT_TABLE_DEFAULT.

Атрибуты

rta_type

тип значения

описание

RTA_UNSPEC

-

игнорируется

RTA_DST

адрес протокола

адрес маршрута назначения

RTA_SRC

адрес протокола

адрес маршрута источника

RTA_IIF

int

индекс входного интерфейса

RTA_OIF

int

индекс выходного интерфейса

RTA_GATEWAY

адрес протокола

шлюз маршрута

RTA_PRIORITY

int

приоритет маршрута

RTA_PREFSRC

RTA_METRICS

int

метрика маршрута

RTA_MULTIPATH

RTA_PROTOINFO

RTA_FLOW

RTA_CACHEINFO

Заполнить эти значения!

RTM_NEWNEIGH, RTM_DELNEIGH, RTM_GETNEIGH

Добавление, удаление или получение информации о записи соседей по таблице (например, запись ARP). В сообщении содержится структура ndmsg:

```
struct ndmsg {

    unsigned char ndm_family;

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

    __u16         ndm_state;    /* состояние */

    __u8          ndm_flags;    /* флаги */

    __u8          ndm_type;
};
struct nda_cacheinfo {

    __u32         ndm_confirmed;

    __u32         ndm_used;

    __u32         ndm_updated;

    __u32         ndm_refcnt;
};

```

В ndm_state содержится битовая маска следующих состояний: NUD_INCOMPLETE

запись кэша в данный момент определяется

NUD_REACHABLE

подтверждённая рабочая запись кэша

NUD_STALE

устаревшая запись кэша

NUD_DELAY

запись ожидает срабатывания таймера

NUD_PROBE

запись кэша в данный момент проверяется повторно

NUD_FAILED

некорректная запись кэша

NUD_NOARP

устройство без кэша назначений

NUD_PERMANENT

статическая запись

Допустимые значения ndm_flags:

NTF_PROXY

запись прокси arp

NTF_ROUTER

маршрутизатор IPv6

Структура rtattr имеет следующие значения для поля rta_type:

NDA_UNSPEC

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

NDA_DST

кэш адресов назначения соседей на сетевом уровне

NDA_LLADDR

кэш адресов соседей на уровне связей

NDA_CACHEINFO

статистика кэша

Если значение поля rta_type равно NDA_CACHEINFO, то присутствует заголовок struct nda_cacheinfo.

RTM_NEWRULE, RTM_DELRULE, RTM_GETRULE

Добавление, удаление или получение правила маршрутизации. Содержит struct rtmsg.

RTM_NEWQDISC, RTM_DELQDISC, RTM_GETQDISC

Добавление, удаление или получение планирования очереди. В сообщении содержится struct tcmsg, а также может быть серия атрибутов.

```
struct tcmsg {

    unsigned char    tcm_family;

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

    __u32            tcm_handle;    /* описатель qdisc */

    __u32            tcm_parent;    /* предок qdisc */

    __u32            tcm_info;
};

```

Атрибуты

rta_type

тип значения

Описание

TCA_UNSPEC

-

не определено

TCA_KIND

строка asciiz

имя план-ания очереди

TCA_OPTIONS

байтовая последовательность

есть параметры qdisc

TCA_STATS

struct tc_stats

статистика qdisc

TCA_XSTATS

относится к qdisc

стат-ка по опр. модулю

TCA_RATE

struct tc_estimator

ограничение по скорости

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

RTM_NEWTCLASS, RTM_DELTCLASS, RTM_GETTCLASS

Добавление, удаление или получение класса трафика. В этих сообщениях содержится структура struct tcmsg, описанная ранее.

RTM_NEWTFILTER, RTM_DELTFILTER, RTM_GETTFILTER

Добавление, удаление или получение информации о фильтре трафика. В этих сообщениях содержится структура struct tcmsg, описанная ранее.

## ВЕРСИИ
Свойство rtnetlink появилось в Linux 2.2.

## ДЕФЕКТЫ
Данная справочная страница не полна.

## СМОТРИТЕ ТАКЖЕ
cmsg(3), rtnetlink(3), ip(7), netlink(7)


sched

title: sched(7)

summary: обзор планирования работы ЦП

text:
# sched(7)

## ИМЯ
sched - обзор планирования работы ЦП

## ОПИСАНИЕ
Начиная с Linux 2.6.23 планировщиком по умолчанию является CFS — «полностью честный планировщик» (Completely Fair Scheduler). Планировщик CFS заменил использовавшийся ранее «O(1)».

### Краткие сведения о программном интерфейсе
Для управления планированием, алгоритмом и приоритетом процессов (более точно, нитей) на ЦП в Linux имеются следующие системные вызовы:

nice(2)

Назначает новое значение уступчивости вызвавшей нити и возвращает новое значение уступчивости.

getpriority(2)

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

setpriority(2)

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

sched_setscheduler(2)

Назначает алгоритм планирования и параметры заданной нити.

sched_getscheduler(2)

Возвращает алгоритм планирования и параметры заданной нити.

sched_setparam(2)

Назначает параметры планирования заданной нити.

sched_getparam(2)

Возвращает параметры планирования заданной нити.

sched_get_priority_max(2)

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

sched_get_priority_min(2)

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

sched_rr_get_interval(2)

Возвращает квант, используемый нитями, которые запланированы «циклическим» (round-robin) алгоритмом планирования.

sched_yield(2)

Заставляет вызывающего освободить ЦП для выполнения других нитей.

sched_setaffinity(2)

(только в Linux) Назначить увязываемый ЦП указанной нити.

sched_getaffinity(2)

(только в Linux) Возвращает увязываемый ЦП указанной нити.

sched_setattr(2)

Назначает алгоритм планирования и параметры заданной нити. Данный системный вызов (есть только в Linux) предоставляет охватывающий набор возможностей sched_setscheduler(2) и sched_setparam(2).

sched_getattr(2)

Возвращает алгоритм планирования и параметры заданной нити. Данный системный вызов (есть только в Linux) предоставляет охватывающий набор возможностей sched_setscheduler(2) и sched_setparam(2).

### Алгоритмы планирования
Планировщик — это часть ядра, которая решает какая запущенная нить будет выполняться процессором следующей. Каждой нити назначается алгоритм планирования и статический приоритет планирования, sched_priority. Планировщик принимает решение на основе данных об алгоритме планирования и статическом приоритете всех нитей системы.

Для нитей, которые планируются одним из обычных алгоритмом планирования (SCHED_OTHER, SCHED_IDLE, SCHED_BATCH), значение sched_priority при принятии решения не используется (должен быть указан 0).

Для процессов, которые планируются одним из алгоритмов реального времени (SCHED_FIFO, SCHED_RR), значение приоритета sched_priority лежит в диапазоне от 1 (низкий) до 99 (высокий) Как и числовые значения, нити реального времени всегда имеют более высокий приоритет чем обычные нити. Но заметим: согласно POSIX.1 от реализации для алгоритмов реального времени требуется поддержка только 32 различных уровней приоритета, и в некоторых системах обеспечивается только этот минимум. В переносимых программах нужно использовать вызовы sched_get_priority_min(2) и sched_get_priority_max(2) для для определения диапазона приоритетов, поддерживаемых определённым алгоритмом.

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

Алгоритм планирования определяет, в какое место списка будет добавлена нить с тем же статическим приоритетом и как она будет перемещаться внутри этого списка.

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

### SCHED_FIFO: планировщик «первым вошёл — первым вышел»
Алгоритм SCHED_FIFO можно использовать только со значениями статического приоритета большими нуля. Это означает, что если нить с SCHED_FIFO готова к работе, то она сразу запустится, а все обычные нити с SCHED_OTHER, SCHED_BATCH или SCHED_IDLE будут приостановлены. SCHED_FIFO — это простой алгоритм планирования без квантования времени. Нити, работающие согласно алгоритму SCHED_FIFO, подчиняются следующим правилам:

1)

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

2)

Когда заблокированная нить с алгоритмом SCHED_FIFO готова к работе, она помещается в конец списка нитей с приоритетом как у неё.

3)

Если вызовом sched_setscheduler(2), sched_setparam(2), sched_setattr(2), pthread_setschedparam(3) или pthread_setschedprio(3) изменяется приоритет выполняющейся или готовой к выполнению нити SCHED_FIFO, задаваемой pid, то результат положения нити в списке зависит от направления изменения приоритета нити:

- Если приоритет нити повышается, то она помещается в конец списка со своим новым приоритетом. В результате, может быть вытеснена выполняемая в этот момент нить с таким же приоритетом.

- Если приоритет нити не изменяется, то её положение в списке выполнения не изменяется.

- Если приоритет нити понижается, то она помещается в начало списка со своим новым приоритетом.

Согласно POSIX.1-2008 изменение приоритета нити (или алгоритма) с помощью какого-либо механизма отличного от pthread_setschedprio(3), должно приводить к размещению нити в конец списка с её приоритетом.

4)

Нить, вызывающая sched_yield(2), будет помещена в конец списка.

Других событий для перемещения нити с алгоритмом SCHED_FIFO в списке ожидания запускаемых нитей с одинаковым статическим приоритетом не существует.

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

### SCHED_RR: планирование выполнения по циклу
SCHED_RR — это просто улучшение SCHED_FIFO. Всё, относящееся к SCHED_FIFO, справедливо и для SCHED_RR за исключением того, что каждой нити разрешено работать непрерывно не дольше максимального кванта времени. Если нить с алгоритмом SCHED_RR работала столько же или дольше, чем квант, то она помещается в конец списка с тем же приоритетом. Нить с алгоритмом SCHED_RR, вытесненная нитью с большим приоритетом, возобновляя работу, использует остаток своего кванта из старого цикла. Длину этого кванта можно узнать, вызвав sched_rr_get_interval(2).

### SCHED_DEADLINE: Модель планирования случайной задачи с предельным сроком
Начиная с версии 3.14, в Linux появился алгоритм планирования с предельным сроком (SCHED_DEADLINE). Сейчас этот алгоритм реализован с помощью GEDF (Global Earliest Deadline First) в совокупности с CBS (Constant Bandwidth Server). Для назначения и выборки данного алгоритма и его атрибутов, нужно использовать системные вызовы (есть только в Linux) sched_setattr(2) и sched_getattr(2).

Случайная задача — одна из последовательности заданий (jobs), где каждое задание активизируется не более чем один раз за промежуток времени. Также у каждого задания есть относительный крайний срок, до которого оно должно завершить выполнение и время вычисления — время ЦП, необходимое для выполнения задания. Момент, когда задача пробуждается из-за выполнения нового задания, называется временем принятия (arrival time) (его ещё называют временем запроса (request time) или временем выпуска (release time). Время начала — это время когда задача начинает выполнение. Абсолютный предельный срок получается сложением относительного предельного срока с временем принятия.

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

```
принятие/пробуждение                    абсолютный предельный срок

     |    время начала                  |

     |        |                         |

     v        v                         v
-----x--------xooooooooooooooooo--------x--------x---

              |<- comp. time ->|

     |<------- относительный предельный срок ------>|

     |<-------------- промежуток времени ------------------->|
```

При назначении нити алгоритма SCHED_DEADLINE с помощью sched_setattr(2) можно указать три параметра: Runtime, Deadline и Period. Эти параметры не обязательно соответствуют вышеупомянутым терминам: на практике, Runtime задаётся чуть больше чем среднее время вычисления (или время вычисления в самом плохом варианте для задач жёсткого реального времени), Deadline равен относительному предельному сроку, а Period равен промежутку времени. Таким образом, при планировании SCHED_DEADLINE мы имеем:

```
принятие/пробуждение                    абсолютный предельный срок

     |    время начала                  |

     |        |                         |

     v        v                         v
-----x--------xooooooooooooooooo--------x--------x---

              |<-- Runtime ------->|

     |<----------- Deadline ----------->|

     |<-------------- Period ------------------->|
```

Три параметра алгоритма с крайним сроком соответствуют полям sched_runtime, sched_deadline и sched_period структуры sched_attr; смотрите sched_setattr(2). Значения этих полей задаются в наносекундах. Если sched_period равно 0, то его значение равно sched_deadline.

Для ядра требуется соблюдение условия:

sched_runtime <= sched_deadline <= sched_period

Также, в текущей реализации, значения всех параметров должны быть не менее 1024 (т. е., чуть более одной микросекунды, ограничено в реализации) и меньше 2^63. При нарушении ограничений sched_setattr(2) завершается с ошибкой EINVAL.

CBS гарантирует отсутствие влияния задача друг на друга, регулируя (throttling) нити, которые пытаются превысить заданное им время выполнения (Runtime).

Чтобы гарантировать выполнение алгоритма планирования крайнего срока, ядро должно предотвращать ситуации, где установка SCHED_DEADLINE нитям не выполнима (не может быть запланирована) для указанных ограничений. Для этого ядро выполняет тест допустимости при назначении или изменении алгоритма SCHED_DEADLINE и атрибутов. В данном тесте вычисляется, выполнимы ли изменения; если нет, то sched_setattr(2) завершается с ошибкой EBUSY.

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

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

Вызов fork(2) в нити, запланированной SCHED_DEADLINE завершается ошибкой EAGAIN, если у нити не установлен флаг reset-on-fork (смотрите далее).

Нить с SCHED_DEADLINE, вызывающая sched_yield(2) приостановит текущее задание и будет ждать начала нового промежутка времени.

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

Для выполнения выбирается нить из списка со статическим приоритетом 0 на основе динамического приоритета, существующего только внутри этого списка. Динамический приоритет основан на значении уступчивости (смотрите ниже) и увеличивается с каждым квантом времени, при котором нить была готова к работе, но ей было отказано в этом планировщиком. Таким образом время равномерно распределяется между всеми нитями с алгоритмом SCHED_OTHER.

В дереве исходного кода ядра Linux алгоритм SCHED_OTHER на самом деле называется SCHED_NORMAL.

### Значение уступчивости
Значение уступчивости — это атрибут, который можно использовать для влияния на планировщик ЦП с целью сделать процесс более популярным (или наоборот) при принятии решений о планировании выполнения. Он учитывается при планировании процессов с SCHED_OTHER и SCHED_BATCH (смотрите ниже). Значение уступчивости можно изменять с помощью nice(2), setpriority(2) или sched_setattr(2).

Согласно POSIX.1, значение уступчивости является атрибутом процесса; то есть нити процесса должны иметь одинаковое значение уступчивости. Однако в Linux значение уступчивости является атрибутом нити: разные нити одного процесса могут иметь разные значения уступчивости.

Диапазон значений уступчивости различается в разных системах UNIX. В современном Linux диапазон: -20 (высокий приоритет) по +19 (низкий приоритет). В других системах диапазон равен -20..20. В самых первых версиях ядра Linux (до Linux 2.0) диапазон равнялся -бесконечность..15.

Степень влияния значения уступчивости на процессы с подобным SCHED_OTHER в разных системах UNIX различна и не одинакова даже между версиями ядра Linux.

С появлением планировщика CFS в ядре 2.6.23, в Linux стал применяться алгоритм, учитывающий относительную разницу значений уступчивости более полно. В текущей реализации каждое различие на единицу между значениями уступчивости двух процессов приводит к умножению приоритета на 1.25, с которым планировщик отдаёт предпочтение процессу с более высоким приоритетом. Это приводит к тому, что самые низкие значения уступчивости (+19) действительно получают очень мало времени ЦП независимо от того, есть ли высокая загрузка системы, и по высоким значениям уступчивости (-20) даётся больше времени на ЦП приложениям, которым это нужно (например, некоторым аудиоприложениям).

Для задания ограничения, до которого можно повышать значение уступчивости непривилегированному процессу, в используется Linux ограничение ресурса RLIMIT_NICE; смотрите setrlimit(2).

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

### SCHED_BATCH: планирование для пакетных процессов
(начиная с Linux 2.6.16) SCHED_BATCH можно использовать только с статическим приоритетом равным нулю. Этот алгоритм похож на SCHED_OTHER в том, что он планирует выполнение нити на основе её динамического приоритета (на основе значения nice). Различие в том, что в этом алгоритме планировщик всегда предполагает, что нить, в основном, использует ЦП. Следовательно, планировщик немного понизит вероятность её следующего пробуждения для того, чтобы эта нить уступила другим при планировании.

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

### SCHED_IDLE: планирование заданий с очень низким приоритетом
(начиная с Linux 2.6.23) SCHED_IDLE можно использовать только с статическим приоритетом равным нулю; значение nice не учитывает в этом алгоритме.

Данный алгоритм предназначен для выполнения заданий с чрезвычайно низким приоритетом (даже ниже чем значение nice +19 в алгоритме SCHED_OTHER или SCHED_BATCH).

### Сброс алгоритма планирования у дочерних процессов
В каждой нити есть флаг планирования reset-on-fork. Когда этот флаг установлен, потомки, создаваемые fork(2), не наследуют привилегированные алгоритмы планирования. Флаг reset-on-fork может быть задан так:

- Логическим сложением флага SCHED_RESET_ON_FORK с аргументом policy при вызове sched_setscheduler(2) (начиная с Linux 2.6.32); или

- заданием флага SCHED_FLAG_RESET_ON_FORK в attr.sched_flags при вызове sched_setattr(2).

Заметим, что константы, используемые в этих двух вызовам имеют разные имена. Состояние флага reset-on-fork может быть получено аналогичным образом с помощью sched_getscheduler(2) и sched_getattr(2).

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

Точнее говоря, если указан флаг reset-on-fork, то к новым потомкам применяются следующие правила:

- Если вызывающая нить имеет алгоритм планирования SCHED_FIFO или SCHED_RR, то у потомков алгоритм сбрасывается в SCHED_OTHER.

- Если у вызывающего процесса значение nice отрицательно, то у потомков значение nice сбрасывается в ноль.

После установки флага reset-on-fork его можно сбросить только, если нить имеет мандат CAP_SYS_NICE. Этот флаг выключается у потомков, созданных через fork(2).

### Привилегии и ограничения по ресурсам
В ядрах Linux до версии 2.6.12, только привилегированные нити (CAP_SYS_NICE) могли устанавливать ненулевое значение статического приоритета (т.е. алгоритм планирования реального времени). Непривилегированные нити могли только установить алгоритм SCHED_OTHER, и это могло быть сделано только, если эффективный пользовательский идентификатор вызывающего совпадал с реальным или эффективным пользовательским идентификатором задаваемого нити (т.е., нити, указываемой в pid).

Для задания или изменения SCHED_DEADLINE нить должна быть привилегированной (CAP_SYS_NICE).

Начиная с Linux 2.6.12, ограничитель ресурса RLIMIT_RTPRIO определяет максимум статического приоритета непривилегированной нити для алгоритмов SCHED_RR и SCHED_FIFO. Правила для изменения алгоритма планирования и приоритета:

- Если непривилегированная нить имеет ненулевое значение мягкого ограничения RLIMIT_RTPRIO, то она может изменять свой алгоритм планирования и приоритет, но при этом значение приоритета не может быть больше чем максимальное значение её текущего приоритета и его мягкого ограничения RLIMIT_RTPRIO.

- Если мягкое ограничение RLIMIT_RTPRIO равно 0, то разрешается только снижать приоритет или переключиться на алгоритм выполнения не реального времени.

- Согласно тем же самым правилам другая непривилегированная нить может также сделать эти изменения, пока эффективный идентификатор пользователя нити, производящей изменение, совпадает с реальным или эффективным идентификатором пользователя изменяемой нити.

- Для политики SCHED_IDLE применяются специальные правила. В ядрах Linux до версии 2.6.39, сменить политику работы непривилегированной нити нельзя, независимо от значения её ограничителя ресурсов RLIMIT_RTPRIO. В ядрах Linux начиная с версии 2.6.39, непривилегированная нить может переключиться на политику SCHED_BATCH или SCHED_OTHER, если её значение уступчивости находится в диапазоне, разрешённом ей ограничителем ресурсов RLIMIT_NICE (см. getrlimit(2)).

Для привилегированных (CAP_SYS_NICE) нитей ограничение RLIMIT_RTPRIO игнорируется; как в старых ядрах, они могут произвольно менять алгоритм планирования и приоритет. Подробней смотрите в getrlimit(2) про RLIMIT_RTPRIO.

### Ограничение использование ЦП процессами реального времени и процессами с крайним сроком
Неблокирующий бесконечный цикл в нити, запланированной алгоритмами SCHED_FIFO, SCHED_RR или SCHED_DEADLINE потенциально может привести к вечному блокированию остальных нитей. До Linux 2.6.25 был только один способ предотвращения заморозки системы бесконтрольными процессами реального времени — запуск (с консоли) оболочки с наивысшим статическим приоритетом, большим чем тестируемое приложение. Это позволяло экстренно прибить тестируемое приложение реального времени, которое не блокируется или завершается как положено.

Начиная с Linux 2.6.25, есть другие способы работы с процессами реального времени и процессами с крайним сроком. Один из них — использовать ограничитель ресурса RLIMIT_RTTIME, задав потолок времени ЦП, которое процесс реального времени может задействовать. Подробней смотрите в getrlimit(2).

Начиная с версии 2.6.25, в Linux также предоставляется два файла в /proc, которые можно использовать для резервирования определённого количества времени ЦП, используемое процессами нереального времени. Резервирование некоторого количества ЦП подобным образом позволяет оставить время на том же ЦП (скажем) оболочке root, через которую можно завершить неконтролируемый процесс. В этих файлах значение времени указывается в микросекундах:

/proc/sys/kernel/sched_rt_period_us

В данном файле задаётся планируемый промежуток времени, который равен 100% полосы ЦП. Значение в этом файле может лежать в диапазоне от 1 до INT_MAX, что даёт рабочий диапазон от 1 микросекунды до, приблизительно, 35 минут. Значение в файле по умолчанию равно 1000000 (1 секунда).

/proc/sys/kernel/sched_rt_runtime_us

Значением в этом файле определяется насколько большой промежуток времени может использоваться всеми процессами реального времени и процессами с крайним сроком в системе. Диапазон значений: от -1 до INT_MAX-1. Значение -1 означает, что время выполнения равно промежутку времени; то есть нет времени ЦП для приложений нереального времени (что соответствует поведению Linux до версии ядра 2.6.25). Значение по умолчанию равно 950000 (0.95 секунды), означающее, что 5% времени ЦП зарезервировано для процессов, планирование которых выполняется не по алгоритму реального времени или алгоритму с крайним сроком.

### Время ответа
Блокированная нить с высоким приоритетом, ожидающая ввода/вывода, освобождает достаточно много процессорного времени до того, как снова начнёт работать. Авторы драйверов устройств могут более эффективно использовать это время, если воспользуются «медленным» обработчиком прерываний.

### Разное
Дочерние процессы наследуют алгоритм планирования и его параметры после fork(2). Алгоритм планирования и параметры сохраняются при вызове execve(2).

Обычно, процессам реального времени необходимо блокировать память для того, чтобы избежать задержек при страничном обмене. Это можно сделать при помощи вызова mlock(2) или mlockall(2).

### Свойство автогруппировки
Начиная с Linux 2.6.38 в ядре появилось свойство, называемое автогруппировкой; оно улучшает интерактивность рабочего окружения несмотря на многопроцессную интенсивную нагрузку ЦП, такую как сборка ядра Linux большим количеством параллельно собирающих процессов (т. е., командой make(1) с флагом -j).

Данное свойств работает совместно с планировщиком CFS, и ядро должно быть собрано с параметром CONFIG_SCHED_AUTOGROUP. В работающей системе свойство можно включать и выключать через файл /proc/sys/kernel/sched_autogroup_enabled; значение 0 выключает свойство, а 1 — включает. Значение по умолчанию равно 1, если ядро не загружалось с параметром noautogroup.

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

При включенной автогруппировке все члены автогруппы помещаются в в одну «группу задач» планировщика ядра. Планировщик CFS использует алгоритм, который уравнивает раздачу циклов ЦП между задачами группы. Преимущество такого подхода заключается в улучшении интерактивности рабочего стола, которую можно описать следующим примером.

Предположим, что есть две автогруппы, выполняющиеся на одном ЦП (т. е., используется система с одним ЦП или с помощью taskset(1) все процессы вытеснены на один ЦП в многопроцессорной системе). Первая группа содержит 10 привязанных к ЦП процессов, запущенных для сборки ядра make -j10. Вторая группа содержит один привязанный к ЦП процесс: видеопроигрыватель. Из-за автогруппировки в том, что каждая из групп получит половину циклов ЦП. То есть, видеопроигрыватель получит 50% циклов ЦП, а не 9% циклов, что, вероятно, привело бы к ухудшению воспроизведения. Ситуация в многопроцессорных системах несколько сложнее, но результат тот же самый: планировщик распределит циклы ЦП между группами задач и автогруппа с большим количеством привязанных к ЦП процессов не истратит все циклы ЦП с ущербом других задач, выполняемых системой.

Членство автогруппы процесса (группу задач) можно увидеть через файл /proc/[pid]/autogroup:

```
$ cat /proc/1/autogroup
/autogroup-1 nice 0
```

Также этот файл можно использовать для изменения полосы пропускания ЦП, выделенной автогруппе. Для этого в файл записывается диапазон «уступчивости», задающий значение уступчивости автогруппы. Допускаемый диапазон: от +19 (низкий приоритет) до -20 (высокий приоритет) (запись через write(2) значений вне это диапазона приводит к ошибке EINVAL).

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

Использование контроллера ЦП cgroups(7) для размещения процессов в cgroup не равную корневой cgroup ЦП, отменяет эффект автогруппировки.

Свойство автогруппировки группирует только процессы, планируемые алгоритмами не реального времени (SCHED_OTHER, SCHED_BATCH и SCHED_IDLE). Оно не группирует процессы, планируемые алгоритмами реального времени и с предельным сроком (deadline). Такие процессы планируются согласно правилам, описанным ранее.

### Значение уступчивости и групповое планирование
При планировании процессов не реального времени (т. е., планируемых по алгоритмам SCHED_OTHER, SCHED_BATCH и SCHED_IDLE), планировщик CFS использует технику называемую «групповое планирование», если ядро было собрано с параметром CONFIG_FAIR_GROUP_SCHED (обычно так и есть).

При групповом планировании нити планируются по «группам задач». Группы задач имеют иерархические связи, берущие начало от начальной группы задач системы, называемой «корневая группа задач». Группы задач формируются согласно следующему:

- Все нити в cgroup ЦП образуют группу задач. Родитель этой группы задач является группой задач соответствующей родительской cgroup.

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

- Если автогруппировка разрешена, то корневая группа задач состоит из всех процессов в корневой cgroup ЦП, которые не были неявно помещены в новую автогруппу.

- Если автогруппировка запрещена, то корневая группа задач состоит из всех процессов в корневой cgroup ЦП.

- Если групповое планирование было запрещено (т. е., ядро собрано без параметра CONFIG_FAIR_GROUP_SCHED), то все процессы системы условно помещаются в одну группу задач.

При групповом планировании значение уступчивости нити влияет на решение о планировании только относительно других нитей в той же группе задач. Это слегка удивляет с точки зрения обычной семантики значения уступчивости в системах UNIX. В частности, если автогруппировка разрешена (по умолчанию во многих дистрибутивах), то применение к процессу setpriority(2) или nice(1) подействует только на планирование относительно других процессов, выполняющихся в том же сеансе (обычно, в том же окне терминала).

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

```
$ echo 10 > /proc/self/autogroup
```

### Возможности выполнения в реальном времени из оригинальной версии Linux
Начиная с версии ядра 2.6.18, Linux постепенно обрастает возможностями выполнения в реальном времени, большая часть которых взята из раннего набора заплат realtime-preempt. Пока заплатки не были полностью включены в основное ядро, их нужно было устанавливать отдельно. Файлы заплаток называются:

```
patch-версия_ядра-rtверсия_заплатки
```

и могут быть скачаны с http://www.kernel.org/pub/linux/kernel/projects/rt/.

Без заплаток и до их полного включения в оригинальное ядро, через параметры ядра предлагается только три класса вытеснения: CONFIG_PREEMPT_NONE, CONFIG_PREEMPT_VOLUNTARY и CONFIG_PREEMPT_DESKTOP, которые, соответственно, не сокращают, частично сокращают и значительно сокращают задержку планирования при наихудшем случае.

С заплатками и после их полного включения в оригинальное ядро, в параметрах ядра появится новый пункт CONFIG_PREEMPT_RT. Если он будет выбран, то Linux преобразуется в обычную операционную систему реального времени. После этого для выполнения нити с настоящим приоритетом реального времени и минимальной задержкой планирования в наихудшем случае используются алгоритмы планирования FIFO и RR.

## ЗАМЕЧАНИЯ
Для ограничения групп процессов потребления ЦП можно использовать контроллер ЦП cgroups(7).

Изначально стандартный Linux представлял собой операционную систему общего назначения для выполнения как фоновых процессов, так и интерактивных приложений, а также нетребовательных приложений реального времени (приложений, которым желательно, чтобы задержки и интервалы времени выдерживались). Хотя ядро Linux 2.6 позволяет вытеснение и новый планировщик O(1) обеспечивает необходимое постоянство планирования и предсказуемое независимое количество активных задач, настоящая работа в реальном времени стала доступна начиная с версии ядра 2.6.17.

## СМОТРИТЕ ТАКЖЕ
chcpu(1), chrt(1), lscpu(1), ps(1), taskset(1), top(1), getpriority(2), mlock(2), mlockall(2), munlock(2), munlockall(2), nice(2), sched_get_priority_max(2), sched_get_priority_min(2), sched_getaffinity(2), sched_getparam(2), sched_getscheduler(2), sched_rr_get_interval(2), sched_setaffinity(2), sched_setparam(2), sched_setscheduler(2), sched_yield(2), setpriority(2), pthread_getaffinity_np(3), pthread_getschedparam(3), pthread_setaffinity_np(3), sched_getcpu(3), capabilities(7), cpuset(7)

Programming for the real world - POSIX.4 by Bill O. Gallmeister, O'Reilly & Associates, Inc., ISBN 1-56592-074-0.

Исходные файлы ядра Linux Documentation/scheduler/sched-deadline.txt, Documentation/scheduler/sched-rt-group.txt, Documentation/scheduler/sched-design-CFS.txt и Documentation/scheduler/sched-nice-design.txt


title: sem_overview(7)

summary: обзор семафоров POSIX

text:
# sem_overview(7)

## ИМЯ
sem_overview - обзор семафоров POSIX

## ОПИСАНИЕ
Семафоры POSIX позволяют процессам и нитям синхронизировать свою работу.

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

Есть два вида семафоров POSIX: именованные семафоры и безымянные семафоры.

Именованные семафоры

Именованные семафоры отличают по именам вида /имя — строка (с null в конце) до NAME_MAX-4 (т. е., 251) символов, состоящая из начальной косой черты и одного или нескольких символов (символ косой черты не допускается). Два процесса могут работать с одним семафором указав его имя в sem_open(3).

Функция sem_open(3) создаёт новый именованный семафор или открывает существующий. После открытия семафора с ним можно работать посредством sem_post(3) и sem_wait(3). Когда процесс закончил использовать семафор, его можно закрыть с помощью sem_close(3). Когда все процессы закончили использовать семафор, его можно удалить из системы с помощью sem_unlink(3).

Безымянные семафоры (семафоры в памяти)

Безымянные семафоры не имеют имени. Семафор размещается в области памяти, которая доступна нескольким нитям (общий семафор для нитей) или процессам (общий семафор для процессов). Общий семафор для нитей размещается в области памяти, которая доступна из нитей процесса, например в глобальной переменной. Общий семафор для процессов должен размещаться в области общей памяти (например, в сегменте общей памяти System V, созданной с помощью shmget(2), или в объекте общей памяти POSIX, созданном с помощью shm_open(3)).

Перед началом использования безымянный семафор должны быть проинициализирован с помощью sem_init(3). После этого с ним можно работать через sem_post(3) и sem_wait(3). Если семафор больше не нужен, то семафор нужно уничтожить с помощью sem_destroy(3) (но до освобождения выделенной для него памяти).

Далее в разделе описываются особенности реализации семафоров POSIX в Linux.

### Версии
До ядра версии 2.6, в Linux поддерживались только безымянные общие семафоры для нитей. В системах с Linux 2.6 и glibc, предоставляющей реализацию нитей NPTL, имеется полная реализация семафоров POSIX.

### Устойчивость
Именованные семафоры POSIX располагаются в ядре. Пока семафор не удалён с помощью sem_unlink(3), он остаётся в системе до её выключения.

### Компоновка
Программы, в которых используется программный интерфейс семафоров POSIX, для компоновки с библиотекой реального времени librt должны компилироваться с помощью cc -pthread.

### Доступ к именованным семафорам через файловую систему
В Linux, именованные семафоры создаются в виртуальной файловой системе, обычно монтируемой в /dev/shm, с именами вида sem.имя (по этой причине длина имени семафора ограничена NAME_MAX-4, а не NAME_MAX символами).

Начиная с Linux 2.6.19, для управления доступом к объектам конкретным пользователям или группам на файлы в этом каталоге могут быть применены ACL.

## ЗАМЕЧАНИЯ
Семафоры System V (semget(2), semop(2) и т. п.) — это старый программный интерфейс семафоров. Семафоры POSIX предоставляют более простой и продуманный интерфейс чем семафоры System V; с другой стороны, семафоры POSIX не так широко распространены (особенно в старых системах), по сравнению с семафорами System V.

## ПРИМЕР
Пример использования функций семафоров POSIX показан в sem_wait(3).

## СМОТРИТЕ ТАКЖЕ
sem_close(3), sem_destroy(3), sem_getvalue(3), sem_init(3), sem_open(3), sem_post(3), sem_unlink(3), sem_wait(3), pthreads(7), shm_overview(7)


session-keyring

title: session-keyring(7)

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

text:
# session-keyring(7)

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

## ОПИСАНИЕ
Связка ключей сеанса — это связка ключей для привязки ключей от имени процесса. Обычно, она создаётся pam_keyinit(8) при входе пользователя в систему и добавляется связь, на которую указывает user-keyring(7). Также, PAM может отозвать связку ключей сеанса при выходе пользователя (обычно, PAM так и делает). Связка ключей сеанса имеет имя (описание) _ses.

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

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

Связка ключей сеанса процесса наследуется при вызове clone(2), fork(2) и vfork(2). Связка ключей сеанса сохраняется при вызове execve(2), даже когда исполняемый файл содержит биты set-user-ID и set-group-ID или имеет другие мандаты. Связка ключей сеанса уничтожается когда завершается последний ссылающийся на неё процесс.

Если процесс при обращении не имеет связки ключей сеанса, то в одних случаях, в качестве связке ключей сеанса будет присоединена user-session-keyring(7), а в других будет создана новая связка ключей сеанса (подробности смотрите в user-session-keyring(7)).

### Специальные операции
Библиотека keyutils предоставляет следующие операции для работы со связками ключей сеанса:

keyctl_join_session_keyring(3)

Данная операция позволяет вызывающему изменить связку ключей сеанса, на которую он подписан. Вызывающий может присоединить существующую связку ключей с заданным именем (описанием), создать новую связку ключей с заданным именем или попросить ядро создать новую «анонимную» связку ключей сеанса с именем «_ses» (данная функция является интерфейсом к keyctl(2) с операцией KEYCTL_JOIN_SESSION_KEYRING).

keyctl_session_to_parent(3)

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

Эти операции также доступны через утилиту keyctl(1):

```
keyctl session
keyctl session - [<прог> <арг1> <арг2> …]
keyctl session <имя> [<прог> <арг1> <арг2> …]
```

и

```
keyctl new_session
```

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


title: shm_overview(7)

summary: обзор общей памяти POSIX

text:
# shm_overview(7)

## ИМЯ
shm_overview - обзор общей памяти POSIX

## ОПИСАНИЕ
API общей памяти POSIX позволяет процессам обмениваться информацией через общую область памяти.

Доступные интерфейсы:

shm_open(3)

Создаёт и открывает новый объект, или открывает существующий объект. Аналог open(2). Вызов возвращает файловый дескриптор, которые используется другими интерфейсами, описанными далее.

ftruncate(2)

Назначает размер общего объекта памяти (размер создаваемого объекта общей памяти равен нулю).

mmap(2)

Отображает объект общей памяти в виртуальное адресное пространство вызвавшего процесса.

munmap(2)

Удаляет отображение объекта общей памяти из виртуального адресного пространства вызвавшего процесса.

shm_unlink(3)

Удаляет объект общей памяти с заданным именем.

close(2)

Закрывает файловый дескриптор (выделенный shm_open(3)), когда он больше не требуется.

fstat(2)

Возвращает структуру stat, в которой описан объект общей памяти. Информация, возвращаемой этим вызовом: размер объекта (st_size), права (st_mode), владелец (st_uid) и группа (st_gid).

fchown(2)

Изменяет владельца объекта общей памяти.

fchmod(2)

Изменяет права на объект общей памяти.

### Версии
Общая память POSIX стала доступна начиная с Linux 2.4 и glibc 2.2.

### Устойчивость
Объекты общей памяти POSIX являются устойчивыми на уровне ядра. Объект будет существовать до самого отключения системы или до тех пор, пока все процессы не разорвут связь с объектом, после чего он может быть удален с помощью shm_unlink(3).

### Компоновка
Программы, в которых используется программный интерфейс общей памяти POSIX, для компоновки с библиотекой реального времени librt должны компилироваться с помощью cc -lrt.

### Доступ к объектам общей памяти через файловую систему
В Linux объекты общей памяти создаются в виртуальной файловой системе (tmpfs(5)), которая обычно монтируется в каталог /dev/shm. Начиная с ядра версии 2.6.19, в Linux поддерживается использование списков контроля доступа (ACL) для управления доступа к объектам в виртуальной файловой системе.

## ЗАМЕЧАНИЯ
Обычно процессы должны синхронизировать свой доступ к объекту общей памяти, например, с использованием семафоров POSIX.

Общая память System V (shmget(2), shmop(2) и так далее) является старым API. POSIX предоставляет более простой и лучше спроектированный интерфейс. С другой стороны, общая память POSIX в какой-то мере менее распространена (особенно на старых системах), чем System V.

## СМОТРИТЕ ТАКЖЕ
fchmod(2), fchown(2), fstat(2), ftruncate(2), mmap(2), mprotect(2), munmap(2), shmget(2), shmop(2), shm_open(3), shm_unlink(3), sem_overview(7)


sigevent

title: sigevent(7)

text:
# sigevent(7)

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

## ОБЗОР

```
#include <signal.h>
```

```
union sigval {          /* Данные, передаваемые с уведомлением */

    int     sival_int;         /* целое */

    void   *sival_ptr;         /* указатель */
};
```

```
struct sigevent {

    int          sigev_notify; /* метод уведомления */

    int          sigev_signo;  /* сигнал уведомления */

    union sigval sigev_value;  /* данные, передаваемые

                                  с уведомлением */

    void       (*sigev_notify_function) (union sigval);

                     /* функция, используемая для нити

                        notification (SIGEV_THREAD) */

    void        *sigev_notify_attributes;

                     /* атрибуты для уведомления нити

                        (SIGEV_THREAD) */

    pid_t        sigev_notify_thread_id;

                     /* ID нити для уведомления (SIGEV_THREAD_ID) */
};
```

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

Определение, приведённое в ОБЗОРЕ, приблизительно: некоторые поля в структуре sigevent могут быть определены как часть объединения. Программы должны использовать только те поля, которые применимы к значению, заданном в sigev_notify.

В поле sigev_notify задаётся как выполняется уведомление. Значением поля может быть:

SIGEV_NONE

«Пустое» уведомление: ничего не делать при возникновении события.

SIGEV_SIGNAL

Уведомить процесс, отправив сигнал, указанный в sigev_signo.

Если сигнал пойман обработчиком сигнала, который зарегистрирован с помощью sigaction(2) с флагом SA_SIGINFO, то следующим полям назначаются значения в структуре siginfo_t, передаваемой во втором аргументе обработчика:

si_code

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

si_signo

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

si_value

В этом поле содержится значение, указанное в sigev_value.

В зависимости от программного интерфейса остальным полям в структуре siginfo_t также могут быть присвоены значения.

Эта информация также доступна, если сигнал принимается с помощью sigwaitinfo(2).

SIGEV_THREAD

Уведомить процесс с помощью вызова sigev_notify_function «как если бы» это была бы начальная функция новой нити (среди возможностей реализации здесь может быть: каждое уведомление таймера приводит к созданию новой нити, или создаётся нить для получения всех уведомлений). Функция вызывается с единственным аргументом sigev_value. Если sigev_notify_attributes не равно NULL, то значение должно указывать на структуру pthread_attr_t, в которой определены атрибуты новой нити (смотрите pthread_attr_init(3)).

SIGEV_THREAD_ID (есть только в Linux)

В настоящее время используется только таймерами POSIX; смотрите timer_create(2).

## СМОТРИТЕ ТАКЖЕ
timer_create(2), aio_fsync(3), aio_read(3), aio_write(3), getaddrinfo_a(3), lio_listio(3), mq_notify(3), aio(7), pthreads(7)