Россия |
Мультиплексирование ввода/вывода и асинхронный ввод/вывод
Приложение 1. Порты Solaris
В Solaris 10 введен новый API, который может быть полезен и в качестве замены select/poll, и для управления запросами асинхронного ввода/вывода. В действительности, select и poll в Solaris 10 реализуются с использованием портов.
Порт представляет собой объект, идентифицируемый файловым дескриптором. Порт создается функцией port_create(3C) и уничтожается системным вызовом close(2). C уже созданным портом можно связывать объекты, способные генерировать события. В настоящее время поддерживаются следующие типы источников событий:
- PORT_SOURCE_AIO - запросы асинхронного ввода-вывода. Событием считается завершение запроса.
- PORT_SOURCE_FD - файловые дескрипторы. При ассоциации файлового дескриптора с портом необходимо указать флаги в формате поля events структуры pollfd ; событиеэти флаги и будут задавать события, которые нас интересуют.
- PORT_SOURCE_TIMER - таймеры.
- PORT_SOURCE_USER - события, генерируемые пользователем при помощи функции port_send(3C).
- PORT_SOURCE_ALERT - события, генерируемые пользователем при помощи функции port_send(3C).
Связывание асинхронного запроса с портомпроисходитвмомент создания запроса, установкой поля aio_sigevent.sigev_notify=SIGEV_PORT. Связывание файлового дескриптора с портом производится функцией port_associate(3C). Судя по количеству и типам параметров, эта функция должна допускать связывание с портом различных объектов, но в Solaris 10 поддерживается единственный тип источника PORT_ SOURCE_FD.
С одним портом можно связывать разнородные источники событий.
После того, как источники связаны с портом, можно получать информацию о возникших событиях функциями port_get(3C) и port_getn(3C). После того, как порт вернул информацию о событии, источник события отсоединяется от порта. Если от этого источника ожидаются какие-то еще события, источник следует связать с портом заново. В случае запросов асинхронного ввода/вывода и таймера смысл отсоединения очевиден. В случае с файлами смысл тоже достаточно легко понять - это защищает нас от неприятных сценариев использования select/poll в многопоточной программе, которые мы рассматривали в ходе этой лекции. При использовании традиционного select/poll существует возможность, что несколько нитей получат один и тот же файловый дескриптор и попытаются что-то с ним сделать. В лучшем случае это приведет к блокировке некоторых нитей, в худшем - к потере данных. Использование портов защищает нас от такого развития событий -после того, как одна из нитей получит файловый дескриптор у порта, он будет отсоединен и остальные нити не смогут получить его, пока он не будет присоединен снова явным образом.
Порты представляют собой новый API. В страницах системного руководства Solaris 10 функции этого API отмечены как evolving (развивающиеся). В настоящее время важным недостатком портов является то, что примитивы синхронизации POSIX Thread API нельзя использовать в качестве источников событий наравне с файловыми дескрипторами и таймерами.
Приложение 2. Установка обработчиков сигналов при помощи sigaction(2)
Системный вызов sigaction(2) дает ранее недоступный уровень управления сигналами. Кроме того, он совместим с требованиями стандарта POSIX. sigaction(2) предоставляет возможности, ранее реализованные в sigset(2): закрывает окно уязвимости при использовании signal(2) и автоматически блокирует рекурсивный вызов функции обработки сигнала.
Параметры act и oact, если они не равны нулю, указывают на экземпляры struct sigaction со следующими полями:
- void (*sa_handler)(int); -Адрес традиционного обработчика сигнала, SIG_IGN или SIG_DFL
- void (*sa_sigaction)(int, siginfo_t *, void *) - Адрес обработчика сигнала в режиме SA_SIGINFO. Реализации могут совмещать это поле с полем sa_handler, поэтому не следует пытаться установить sa_handler и sa_sigaction в одной структуре.
- sigset_t sa_mask -Маска сигналов, которые должны быть заблокированы, когда вызывается функция обработки сигнала.
- int sa_flags - Флаги, управляющие доставкой сигнала.
Если аргумент act ненулевой, он указывает на структуру, определяющую новые действия, которые должны быть предприняты при получении сигнала sig. Если аргумент oact ненулевой, он указывает на структуру, где сохраняются ранее установленные действия для этого сигнала.
Поле sa_flags в struct sigaction формируется побитовым ИЛИ следующих значений:
- SA_ONSTACK -Используется для обработки сигналов на альтернативном сигнальном стеке.
- SA_RESETHAND - Во время исполнения функции обработки сбрасывает реакцию на сигнал к SIG_DFL ; обрабатываемый сигнал при этом не блокируется.
- SA_NODEFER - Во время обработки сигнала сигнал не блокируется.
- SA_RESTART -Системные вызовы, которые будут прерваны исполнением функции обработки, автоматически перезапускаются.
- SA_SIGINFO -Используется для доступа к подробной информации о процессе, исполняющем сигнальный обработчик, такой как причина возникновения сигнала и контекст процесса в момент доставки сигнала.
- SA_NOCLDWAIT - Подавляет создание процессов-зомби.
- SA_NOCLDSTOP -Подавляет генерацию SIGCHLD, когда порожденные процессы останавливаются или возобновляются.