Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
Шрифт:
Обработка команды «get» («получить») на этапе 4 во многом аналогична (по части приведения типов), кроме того, что на этот раз мы записываем данные в структуру вместо считывания из нее. Заметьте, что мы также присваиваем переменной nbytes число байт, которые мы хотим возвратить клиенту. В случае более сложного доступа к данным вы должны были бы возвратить размер области данных (т.е. если бы эта область была бы структурой, вам нужно было бы возвратить ее размер).
Наконец, для возврата данных клиенту мы должны вспомнить, что клиент ожидает не только возвращаемые данные (если таковые
Вспомните рассуждения про следующую за заголовком область данных из примера io_write, приведенного выше. Мы утверждали, что байты, расположенные сразу после заголовка, могут как быть полноценными, так и нет (то есть возможны случаи, когда область данных со стороны клиента была считана лишь частично) — в зависимости от того, сколько данных считала библиотека администратора ресурсов. Затем мы говорили о том, что было бы неэффективно пытаться «сэкономить» лишнюю операцию обмена сообщениями и «повторно использовать» область данных. Однако, в случае с devctl все обстоит несколько иначе, особенно если количество передаваемых данных достаточно невелико (как было и в наших примерах). Здесь у нас есть неплохой шанс того, что данные от клиента были-таки считаны в область данных целиком, и тогда повторное их считывание будет напрасной тратой сил. Узнать, сколько у вас доступно пространства, очень просто: поле size («размер») структуры ctp содержит число байт, доступных для вас, начиная с параметра msg. Размер доступной области данных, расположенной за буфером сообщений, вычисляется как разность между размером буфера сообщений и полем size структуры ctp:
Отметим, что этот размер будет действителен также и в случае возврата данных клиенту (как при команде DCMD_AUDIO_GET_SAMPLE_RATE).
Для всего, что превосходит по размеру выделенную область, вам придется получать данные от клиента так же, как мы это делали в примере с io_write (см. выше), а также выделить буфер для возврата данных клиенту.
Дополнительно
Теперь, после того как мы овладели «основами» построения администраторов ресурсов, пришло время рассмотреть более сложные вопросы. К ним относятся:
• расширение OCB;
• расширение атрибутной записи;
• блокирование в пределах администратора ресурсов;
• возврат элементов каталога.
Расширение OCB
В ряде случаев у вас может возникнуть необходимость расширения OCB. Процедура эта является относительно безболезненной. Обычно OCB расширяют дополнительными флагами, характеризующими каждый конкретный open. Один такой флаг можно было бы использовать с обработчиком io_unblock для кэширования значения флага ядра _NTO_MI_UNBLOCK_REQ (подробнее см. параграф «Применение флага _NTO_MI_UNBLOCK_REQ» в главе «Обмен сообщениями»).
Для расширения блока OCB вам нужно будет обеспечить две дополнительных функции: одну для выделения OCB, и одну — для его освобождения. Затем вы должны будете привязать эти две функции к записи точки монтирования. (Да-да, совершенно верно — вам понадобится запись точки монтирования, даже если только для этого.) И наконец, вы должны будете определить ваш собственный тип OCB, чтобы все прототипы в программе были корректны.
Давайте рассмотрим сначала описание типа OCB, а затем уже поглядим, как переопределяются функции:
Это сообщает включаемому файлу
Вот наш расширенный OCB:
А вот код, иллюстрирующий, как переопределяются функции выделения и освобождения OCB в записи точки монтирования:
После этого остается только привязать запись точки монтирования к атрибутной записи:
Функции my_ocb_calloc и my_ocb_free отвечают за выделение обнуленного расширенного OCB и освобождения OCB, соответственно. Вот их прототипы: