Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
Шрифт:
Самый первый элемент структуры (nfuncs) указывает, насколько она велика (то есть сколько элементов она содержит). Текущее значение этого элемента содержится в константе _RESMGR_IO_NFUNCS.
Отметим, что списки параметров в таблице функций ввода/вывода также довольно однообразны. Первый параметр — ctp, второй параметр — msg, как и у обработчиков из таблицы функций установления соединения.
Третий параметр, однако, отличается. Этот параметр называется ocb, что расшифровывается как «Open Context Block» — «блок открытого контекста». Этот блок содержит контекст, созданный обработчиком сообщения установления соединения (например, в результате клиентского запроса open) и доступный функциям ввода/вывода.
Как уже упоминалось ранее, когда придет время заполнять таблицы функций, рекомендуется пользоваться для этого функцией iofunc_func_init, чтобы сначала загрузить таблицы POSIX-обработчиками по умолчанию. Если же вам будет нужно переопределить обработчики сообщений определенного типа, вы сможете просто заменить POSIX-обработчики по умолчанию на свои
И, наконец, еще одна структура данных используется базовым уровнем библиотеки, чтобы отслеживать кое-какую информацию для себя. Вам не следует изменять содержимое этой структуры, за исключением одного элемента — вектора ввода/вывода iov.
Вот эта структура данных (взято из
Как и в случае с другими структурами данных, я позволил себе опустить зарезервированные поля.
Давайте взглянем на ее содержимое.
rcvid | Идентификатор отправителя, полученный от MsgReceivev. Указывает, кому вы должны ответить (если вы намерены отвечать самостоятельно). |
info | Содержит информационную структуру, возвращаемую функцией MsgReceivev в основном цикле приема сообщений библиотеки администратора ресурсов. Полезна для получения информации о клиенте, включая дескриптор узла, идентификатор процесса (PID), идентификатор потока и т.д. Подробнее см. документацию по функции MsgReceivev. |
msg | Указатель на объединение (union) всех возможных типов сообщений. Практически бесполезен, потому что каждая из ваших функций-обработчиков получает соответствующий элемент объединения вторым параметром. |
ctrl | Указатель на управляющую структуру, которую вы передали в самом начале. Опять же, для вас этот параметр не очень полезен, но зато полезен для библиотеки администратора ресурсов. |
id | Идентификатор точки монтирования, которой предназначалось сообщение. Когда вы вызывали resmgr_attach, она вернула вам небольшой целочисленный идентификатор. Это и есть значение id. Отметим, что вы вероятнее всего никогда не будете использовать этот параметр самостоятельно, а будете полагаться вместо этого на атрибутную запись, передаваемую вам обработчиком io_open. |
status | Сюда ваша функция-обработчик помещает результат выполнения операции. Отметим, что вы должны всегда использовать макрос _RESMGR_STATUS для заполнения этого поля. Например, если вы обрабатываете сообщение установления соединения от функции open, причем ваш администратор ресурса предоставляет доступ «только для чтения», а клиент хотел открыть ресурс на запись, вы возвратите клиенту через errno код EROFS при помощи (обычно) _RESMGR_STATUS(ctp, EROFS) . |
offset | Текущее смещение (в байтах) в клиентском буфере сообщений. Имеет смысл для базового уровня библиотеки только при чтении составных сообщений функцией resmgr_msgreadv. |
size | Этот параметр говорит, сколько байт в буфере сообщения, переданном вашей функции-обработчику, являются достоверными. Это важная цифра, поскольку она указывает на то, требуется ли читать дополнительные данные от клиента (например, если не все данные были считаны базовым уровнем библиотеки), и надо ли выделить память для ответа клиенту (например, для ответа на запрос read). (Отметим, что в версии 2.00 есть ошибка, из-за которой это поле не заполняется в случае несоставного сообщения установления соединения. Все остальные сообщения обрабатываются корректно. Обходной путь здесь (и только здесь!) заключается в использовании параметра msglen структуры info.) |
iov | Таблица векторов ввода/вывода, в которую вы можете записывать возвращаемые значения, если это необходимо. Например, когда клиент вызывает read, и у вас вызывается соответствующий обработчик read, вам может потребоваться возвратить клиенту данные. Можно задать эти данные при помощи массива iov и возвратить что-нибудь типа _RESMGR_NPARTS(2) , указав тем самым (в нашем случае), векторы iov[0] и iov[1] содержат данные для клиента. Заметьте, что массив iov определен как одноэлементный. Однако, заметьте также, что он очень удобно расположен в конце структуры. Фактическое число элементов в массиве iov определяете вы сами, когда присваиваете значение полю nparts_max вышеупомянутой управляющей структуры (см. параграф «Управляющая структура resmgr_attr_t »). |
Структура администратора ресурсов
Теперь, когда мы имеем представление о структурах данных, мы можем обсудить взаимодействие между компонентами, которые вам предстоит написать, чтобы ваш администратор
Мы рассмотрим:
• Функцию resmgr_attach и ее параметры;
• Подстановку своих собственных функций;
• Общую схему работы администратора ресурсов;
• Сообщения, которые должны бы быть сообщениями установления соединения, но таковыми не являются;
• Составные сообщения.
Как вы уже видели в приведенном выше примере с администратором
Давайте исследуем по порядку ее аргументы и посмотрим, как они применяются.
dpp | Дескриптор диспетчера (dispatch handle). Обеспечивает интерфейсу диспетчеризации возможность управлять приемом сообщений для вашего администратора ресурсов. |
resmgr_attr | Управляет характеристиками администратора ресурсов, как обсуждалось ранее. |
path | Точка монтирования, которую вы регистрируете. Если вы регистрируете дискретную точку монтирования (как, например, в случае с /dev/null или /dev/ser1 ), клиент должен указывать ее точно, без каких бы то ни было дополнительных компонентов имени пути в ее конце. Если вы регистрируете каталоговую точку монтирования (как было бы, например, в случае с сетевой файловой системой, монтируемой как /nfs ), то соответствие тоже должно быть точным, но с той оговоркой, что в этом случае продолжение имени пути допускается; то, что идет после точки монтирования, будет передано функции установления соединения (например, имя пути /nfs/etc/passwd даст совпадение с точкой монтирования сетевой файловой системой, а «остатком» будет etc/passwd ). (Эта особенность, кстати, может пригодиться и там, где на первый взгляд логичнее было бы регистрировать дискретную точку монтирования — см. параграф «Регистрация префикса» раздела «Взгляд со стороны администратора ресурсов» — прим. ред.) |
file_type | Класс администратора ресурсов. См. ниже. |
flags | Дополнительные флаги, управляющие поведением вашего администратора ресурсов. Эти флаги выбираются из множества _RESMGR_FLAG_BEFORE, _RESMGR_FLAG_AFTER, _RESMGR_FLAG_DIR и константы 0. Флаги «BEFORE» (букв, «перед») и «AFTER» (букв, «после») указывают на то, что ваш администратор ресурсов хочет зарегистрироваться на данной точке монтирования перед или, соответственно, после других. Эти два флага могут быть полезны, если надо реализовать объединенные файловые системы. Мы вскоре вернемся к взаимосвязи этих флагов. Флаг «DIR.» («каталог») указывает на то, что ваш администратор ресурса хочет обслуживать указанную точку монтирования и все, что находится ниже ее — этот стиль характерен для администратора файловой системы, в противоположность администратору ресурсов, регистрирующему дискретную точку монтирования. |
connect_funcs и io_funcs | Эти параметры являются просто списком функций установления соединения и функций ввода/вывода, которые вы хотите привязать к точке монтирования. |
handle | Это «расширяемая» структура (также известная как «атрибутная запись»), описывающая монтируемый ресурс. Например, в случае последовательного порта вы могли бы расширить стандартную атрибутную запись POSIX-уровня информацией о базовом адресе последовательного порта, скорости обмена в бодах, и т.д. |
Вы можете вызывать функцию resmgr_attach столько раз, сколько вам захочется зарегистрировать различных точек монтирования. Вы также можете вызывать функцию resmgr_attach из тела функций установления соединения или ввода/вывода — эта аккуратная особенность позволяет вам «создавать» устройства «на лету».
Когда вы определились с точкой монтирования и хотите ее зарегистрировать, вы должны сообщить администратору процессов, хочет ли ваш администратор ресурсов обрабатывать запросы от кого попало или только от клиентуры, которая помечает свои сообщения установления соединения специальными метками. Например, рассмотрим драйвер очередей сообщений POSIX (mqueue). Ему совершенно ни к чему «обычные» вызовы open от старых добрых клиентов — он просто не будет знать, что с ними делать. Он примет сообщения только от тех клиентов, которые используют POSIX-вызовы mq_open, mq_receive, и т.п. Чтобы не позволять администратору процессов даже перенаправлять «обычные» запросы администратору очередей mqueue, у этого администратора в параметре параметр file_type задается значение _TYPE_MQUEUE. Это означает, что когда клиент пытается с помощью администратора процессов выполнить разрешение имени, при этом явно не определив, что хочет поговорить с администратором ресурсов, зарегистрированным как _FTYPE_MQUEUE, администратор процессов не будет даже рассматривать администратор mqueue как возможный вариант.
Если только вы не делаете что-либо уж очень специфичное, вам лучше всего подойдет значение file_type, равное _FTYPE_ANY, означающее, что ваш администратор ресурсов готов обработать запрос от любого клиента. Полный список именованных констант _FTYPE_* приведен в файле
Что касательно флагов «BEFORE» и «AFTER», тут все становится интереснее. Вы можете задать либо один из этих флагов, либо константу 0.
Давайте посмотрим, как это работает. Стартуют несколько администраторов ресурсов, в указанном в таблице порядке. В таблице также приведены флаги, указанные каждым из них в параметре flags. Взгляните на получившуюся очередность.