Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
Шрифт:
Нам надо придумать какой-то вызов API для клиента — мы, конечно, можем принудить клиента «вручную» заполнять структуры
Теперь мы имеем хорошо документированную функцию adjust_xyz, которая выполняет нечто полезное для клиента. Заметьте, что для передачи данных
Это пример применения функции io_msg (ее мы скоро опишем — это не стандартный библиотечный вызов!). Функция io_msg колдует над сборкой сообщения _IO_MSG. Чтобы уйти от проблемы функции devctl с наличием только одного параметра размера, мы дали функции io_msg два таких параметра: один — для ввода (
Последнее, что я сделал в функции adjust_xyz, — это зависимость от переменной global_fd, содержащей дескриптор файла администратора ресурса. Есть, опять же, множество способов обработки этого:
• Скрыть дескриптор файла внутри функции io_msg (это было бы полезно, если бы вы пожелали избавиться от необходимости передавать дескриптор файла с каждым вызовом; это хорошо в случаях, когда вы собираетесь обмениваться сообщениями только с одним администратором ресурса, и не подходит в качестве универсального решения).
• Передавать от клиента дескриптор файла каждому вызову функции библиотеки API (полезно, если клиент хочет разговаривать с администратором ресурса еще и другими способами, например, стандартными POSIX-вызовами на основе файловых дескрипторов типа read, или если клиент должен уметь общаться с несколькими администраторами ресурсов).
Вот текст функции io_msg:
Отметьте
несколько вещей.В функции io_msg для «инкапсуляции» специального сообщения (передаваемого в параметре «msg») в структуру io_message использован двухкомпонентный вектор ввода-вывода IOV.
Структура io_message была предварительно обнулена, и в ней был задан тип сообщения (_IO_MSG), а также инициализировано поле cmd (это будет использовано администратором ресурса для определения типа посылаемого сообщения).
В качестве кода завершения функции io_msg использовался непосредственно код завершения MsgSendv.
Единственная «забавная» вещь, которую мы тут сделали, касается поля mgrid. QSSL резервирует для данного поля диапазон значений со специальным поддиапазоном для «неофициальных» драйверов. Этот поддиапазон ограничен значениями от _IOMGR_PRIVATE_BASE до IOMGR_PRIVATE_MAX соответственно. Если вы разрабатываете глубоко встраиваемую систему и хотите быть уверены, что ваш администратор ресурса не получит никаких неподходящих сообщений, то смело можете использовать значения из этого специального диапазона. С другой стороны, если вы разрабатываете в большей степени «настольную» или «обычную» систему, вы можете захотеть точно проконтролировать, будут ли вашему администратору ресурса приходит несоответствующие сообщения или нет. В этом случае вам нужно будет обратиться в QSSL за значением mgrid, зарезервированным специально для вас — никто, кроме вас, не должен использовать это номер. Посмотрите файл
или QSSL назначила нам специальный поддиапазон:
А что если клиент, которого вы переносите, использует администратор ввода/вывода? Как адаптировать его для QNX/ Neutrino? Ответ прост: мы уже это сделали. Установив интерфейс на основе файловых дескрипторов, мы уже используем администратор ресурса. В QNX/Neutrino вам почти никогда не придется использовать интерфейс «сырых» сообщений. Почему?
1. Вам пришлось бы самим беспокоиться о сообщении _IO_CONNECT, поступившим с клиентским вызовом open, или искать способ поиска администратор ресурса, альтернативный использованию open.
2. Вам пришлось бы искать способ сопоставить клиенту конкретный контекстный блок в администраторе ресурса. Это, конечно, не ракетная техника, но поработать придется.
3. Вам придется инкапсулировать все ваши сообщения вручную вместо использования стандартных POSIX-функций, которые бы сделали эту работу за вас.
4. Ваш администратор ресурса не будет работать с приложениями на основе stdin/stdout. В примере с аудиодрайвером вы не смогли бы просто так выполнить
В QNX4 единственным способом передачи неблокирующего сообщения было создание прокси — это делалось с помощью функции qnx_proxy_attach. Эта функция возвращает идентификатор прокси (proxy ID), (он выбирается из того же самого пространства номеров, что и идентификаторы процессов), к которому вы затем можете применить функцию Trigger или возвратить его из функции обработки прерывания (см. ниже).