MQ_OVERVIEW(7)

ИМЯ
mq_overview - обзор очередей сообщений POSIX

ОПИСАНИЕ
Очереди сообщений POSIX позволяют процессам обмениваться данными в виде сообщений. Данный программный интерфейс отличается от используемого в очередях сообщений System V (msgget(2), msgsnd(2), msgrcv(2), etc.), но предоставляет схожие возможности. Очереди сообщений создаются и открываются с помощью mq_open(3); эта функция возвращает дескриптор очереди сообщений (mqd_t), который используется в последующих вызовах для ссылки на открытую очередь сообщений. Каждая очередь сообщений описывается именем в виде /некое_имя; оно представляет собой строку с null в конце и длиной до NAME_MAX (т. е., 255) символов, состоящую из начальной косой черты, одного и более символа (любого, кроме косой черты). Два процесса могут работать через одну очередь, если укажут одинаковое имя в mq_open(3). Сообщения передаются в и из очереди с помощью функций mq_send(3) и mq_receive(3). Когда процесс прекращает использовать очередь, он закрывает её с помощью функции mq_close(3), и если очередь больше не нужна, то она может быть удалена с помощью функции mq_unlink(3). Атрибуты очереди можно получить и (в некоторых случаях) изменить с помощью функций mq_getattr(3) и mq_setattr(3). Процесс может запросить асинхронное уведомление о поступлении сообщения в пустую очередь с помощью функции mq_notify(3). Дескриптор очереди сообщений — это ссылка на открытое описание очереди сообщений (сравнимо с open(2)). После вызова fork(2) потомок наследует копии дескрипторов очередей сообщений родителя и эти дескрипторы ссылаются на те же открытые описания очередей сообщений родителя. Соответствующие дескрипторы очередей сообщений двух процессов используют общий флаг (mq_flags), который связан с открытым описанием очереди сообщений. У каждого сообщения есть приоритет, и сначала в принимающий процесс всегда доставляются сообщения наивысшим приоритетом. Диапазон приоритетов сообщений: 0 (низший) — sysconf(_SC_MQ_PRIO_MAX) - 1 (высший). В Linux, sysconf(_SC_MQ_PRIO_MAX) возвращает 32768, но в POSIX.1 требуется реализация поддержки только диапазона приоритетов от 0 до 31; некоторые реализации предоставляют только этот диапазон.

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

  Библиотечные интерфейсы и системные вызовы
В большинстве случаев, перечисленные выше библиотечные интерфейсы mq_*() реализуются поверх системных вызовов с теми же именами. Исключения из этого правила перечислены в следующей таблице:
    Библиотечный интерфейс | Системный вызов
    mq_close(3) | close(2)
    mq_getattr(3) | mq_getsetattr(2)
    mq_notify(3) | mq_notify(2)
    mq_open(3) | mq_open(2)
    mq_receive(3) | mq_timedreceive(2)
    mq_send(3) | mq_timedsend(2)
    mq_setattr(3) | mq_getsetattr(2)
    mq_timedreceive(3) | mq_timedreceive(2)
    mq_timedsend(3) | mq_timedsend(2)
    mq_unlink(3) | mq_unlink(2)

  Версии
Поддержка очередей сообщений POSIX началась в ядре Linux версии 2.6.6. Поддержка в glibc предоставляется с версии 2.3.4.

  Конфигурация ядра
Поддержка очередей сообщений POSIX включается параметром настройки ядра CONFIG_POSIX_MQUEUE. Данный параметр включён по умолчанию.

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

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

  Интерфейсы /proc
Для ограничения потребления очередями сообщений POSIX памяти ядра и задания атрибутов по умолчанию для новых очередей сообщений, можно использовать следующие интерфейсы:

/proc/sys/fs/mqueue/msg_default (начиная с Linux 3.5)
    В данном файле задаётся значение, которое используется для mq_maxmsg в создаваемой новой очереди с помощью вызова mq_open(3) со значением attr равным NULL. Значение для этого файла по умолчанию равно 10. Минимальное и максимальные значение такие же как для /proc/sys/fs/mqueue/msg_max. Значение по умолчанию mq_maxmsg у новой очереди будет меньше msg_default и msg_max. До Linux 2.6.28 значение mq_maxmsg по умолчанию равнялось 10; с Linux 2.6.28 по Linux 3.4 значение по умолчанию равнялось ограничению msg_max.

/proc/sys/fs/mqueue/msg_max
    Данный файл можно использовать для просмотра и изменения значения максимального количества сообщений в очереди. Это значение служит верхним пределом для аргумента attr->mq_maxmsg, указываемого в mq_open(3). Значение msg_max по умолчанию равно 10. Минимальное значение равно 1 (10 в ядрах до версии 2.6.28). Верхний предел равен HARD_MSGMAX. Ограничитель msg_max игнорируется для привилегированных процессов (CAP_SYS_RESOURCE), но, тем не менее, учитывается предел HARD_MSGMAX. Определение HARD_MSGMAX изменялось в разных версиях ядра следующим образом:

    *   До Linux 2.6.32: 131072 / sizeof(void *)

    *   Linux 2.6.33 по 3.4: (32768 * sizeof(void *) / 4)

    *   Начиная с Linux 3.5: 65536

/proc/sys/fs/mqueue/msgsize_default (начиная с Linux 3.5)
    В данном файле задаётся значение, которое используется для mq_msgsize в создаваемой новой очереди с помощью вызова mq_open(3) со значением attr равным NULL. Значение для этого файла по умолчанию равно 8192 (байты). Минимальное и максимальные значение такие же как для /proc/sys/fs/mqueue/msgsize_max. Если msgsize_default превышает msgsize_max, то значение mq_msgsize для новой очереди по умолчанию ограничивается msgsize_max.До Linux 2.6.28 значение mq_msgsize по умолчанию равнялось 8192; с Linux 2.6.28 по Linux 3.4 значение по умолчанию равнялось ограничению msgsize_max.

/proc/sys/fs/mqueue/msgsize_max
    Данный файл можно использовать для просмотра и изменения максимального размера сообщения. Это значение служит верхним пределом для аргумента attr->mq_msgsize, указываемого в mq_open(3). Значение msgsize_max по умолчанию равно 8192 байта. Минимальное значение равно 128 (8192 в ядрах до версии 2.6.28). Верхний предел msgsize_max изменялся в разных версиях ядер следующим образом:

    *   До Linux 2.6.28 верхний предел был равен INT_MAX.

    *   С Linux 2.6.28 по 3.4 предел равен 1048576.

    *   Начиная с Linux 3.5 предел равен 16777216 (HARD_MSGSIZEMAX).

    Предел msgsize_max игнорируется для привилегированных процессов (CAP_SYS_RESOURCE), но, начиная с Linux 3.5, накладывается ограничение HARD_MSGSIZEMAX.

/proc/sys/fs/mqueue/queues_max
    Данный файл можно использовать для просмотра и изменения системного ограничения на количество сообщений в очереди. Значение queues_max по умолчанию равно 256. У queues_max нет верхнего предела; привилегированные процессы (CAP_SYS_RESOURCE) могут превышать ограничение (но смотрите ДЕФЕКТЫ).

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

  Монтирование файловой системы очереди сообщений
В Linux очереди сообщений создаются в виртуальной файловой системе (другие реализации могут делать также, но, вероятно, по-другому). Данная файловая система может быть смонтирована (суперпользователем) с помощью команд:
# mkdir /dev/mqueue
# mount -t mqueue none /dev/mqueue
Закрепляющий бит устанавливается на каталог назначения автоматически. После примонтирования файловой системы очередь сообщений в системе можно просматривать и изменять с помощью команд как с обычными файлами (например, ls(1) и rm(1)). Содержимое каждого файла в каталоге состоит из одной строки, в которой представлена информация об очереди:
$ cat /dev/mqueue/mymq
QSIZE:129     NOTIFY:2    SIGNO:0    NOTIFY_PID:8260
Эти поля означают следующее:

QSIZE
    Количество байтов данных во всех сообщениях очереди (но смотрите ДЕФЕКТЫ).

NOTIFY_PID
    Если это значение не равно нулю, то процесс с данным PID использовал mq_notify(3) для регистрации асинхронных уведомлений о сообщениях, а оставшиеся поля описывают как производится уведомление.

NOTIFY
    Способ уведомления: 0 — SIGEV_SIGNAL; 1 — SIGEV_NONE; 2 — SIGEV_THREAD.

SIGNO
    Номер сигнала, который будет использован для SIGEV_SIGNAL.

  Реализация дескрипторов очереди сообщений в Linux
В Linux дескриптор очереди сообщений представляет собой файловый дескриптор (в POSIX не требуется этого от реализации). Это означает, что за дескриптором очереди сообщений можно следить с помощью select(2), poll(2) или epoll(7). Это является непереносимым свойством. Флаг close-on-exec (смотрите open(2)) устанавливается автоматически на файловом дескрипторе, возвращаемом mq_open(2).

  Пространства имён IPC
Обсуждение связи объектов System V IPC с пространствами IPC смотрите в namespaces(7).

ЗАМЕЧАНИЯ
Очереди сообщений System V (msgget(2), msgsnd(2), msgrcv(2) и т. д.) — более старый программный интерфейс обмена сообщениями между процессами. Очереди сообщений POSIX имеют более проработанный интерфейс чем очереди сообщений System V; с другой стороны, очереди сообщений POSIX не так широко распространены (особенно в старых системах) чем очереди сообщений System V. В Linux (версия 2.6.26) пока нет поддержки использования списков контроля доступа (ACL) для очередей сообщений POSIX.

ДЕФЕКТЫ
В Linux версиях с 3.5 по 3.14 ядро устанавливает верхний предел в 1024 (HARD_QUEUESMAX) на значение ограничения queues_max и это влияет даже на привилегированные процессы. Это предельное значение было удалено в Linux 3.14, а также есть заплаты к стабильным ядрам версий с 3.5.x по 3.13.x для удаления этого предела. Первоначально реализованное (и описанное) поле QSIZE показывало общее количество (пользовательских) байт всех сообщений в очереди. Некоторые изменения в Linux 3.5 непреднамеренно изменили это поведение, и поле стало также включать байты издержек ядра, которые требуются для хранения сообщений в очереди. Это было исправлено в Linux 4.2 (и более ранних стабильных ядрах), и теперь снова считаются байты только пользовательских сообщений в очереди.

ПРИМЕР
Пример использования функций работы с очередью сообщений смотрите в mq_notify(3).

СМОТРИТЕ ТАКЖЕ
getrlimit(2), mq_getsetattr(2), poll(2), select(2), mq_close(3), mq_getattr(3), mq_notify(3), mq_open(3), mq_receive(3), mq_send(3), mq_unlink(3), epoll(7), namespaces(7)