Чтение онлайн

на главную - закладки

Жанры

Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform

Кёртен Роб

Шрифт:
Этап 8

Сопоставьте этот этап с этапом 6. Здесь мы только разблокируем клиента и не выполняем больше никаких действий. Также обратите внимание, что функции MsgReply не передается никакой области данных, потому что в этом случае данные мы не возвращаем.

Этап 9

И наконец, на этапе 9 мы выполняем действия, не зависящие от того, возвращаем мы данные клиенту или нет. Поскольку мы уже сами разблокировали клиента при помощи MsgReply, мы, конечно же, не хотим, чтобы это попыталась сделать еще и библиотека администратора ресурсов. Поэтому мы сообщаем ей, что мы уже сделали это сами, возвратом _RESMGR_NOREPLY.

Эффективное применение
других функций обмена сообщениями

Как вы помните из главы «Обмен сообщениями», мы упоминали еще несколько функций обмена сообщениями, а именно — функции MsgWrite, MsgWritev и MsgReplyv. Повод, в связи с которым я снова упоминаю здесь эти функции, состоит в том, что ваша функция io_read может быть превосходным местом для их применения. В простом примере, показанном выше, мы возвращали непрерывный массив данных из постоянного места в памяти. В реальной же жизни вам может понадобиться возвратить, скажем, множество фрагментов данных из различных выделенных вами буферов. Классическим примером такого случая является циклический буфер, который часто применяется, например, в драйверах последовательных устройств. Часть данных может быть размещена в конце буфера, другая часть — в начале. В этом случае для возврата обеих частей данных вам понадобилось бы передать MsgReplyv двухэлементный вектор ввода/вывода (IOV), где первый элемент содержал бы адрес (и длину) «нижней» части данных, а второй — адрес (и длину) «верхней» части. Или же, если вы ожидаете прибытия данных частями, вы могли бы вместо этого использовать функции MsgWrite или MsgWritev для записи данных в адресное пространство клиента по мере их поступления, а затем выдать заключительный вызов MsgReply или MsgReplyv, чтобы разблокировать клиента. Как мы уже показали выше, функция MsgReply может и не передавать никаких данных— вы можете использовать ее просто для того, чтобы разблокировать клиента.

Простой пример функции io_write

Это был простой пример функции io_read; давайте теперь перейдем к функции io_write. Основной камень преткновения, связанный с io_write, — получить доступ к данным. Поскольку библиотека администратора ресурсов считывает лишь незначительную часть сообщения от клиента, переданные клиентом данные (они идут сразу после заголовка _IO_WRITE) могут быть приняты функцией io_write только частично. Простой пример — представьте себе клиента, записывающего один мегабайт. Библиотекой администратора ресурсов будут считаны только заголовок сообщения и несколько байт данных. Остальная часть мегабайта остается по-прежнему доступной на клиентской стороне — администратор ресурсов при желании может к ней обращаться.

Реально рассмотрения заслуживают только два случая:

• все содержимое сообщения клиентской функции write было считано библиотекой администратора ресурсов полностью; или

• этого не произошло.

Судьбоносное решение, однако, состоит в ответе на следующий вопрос: «Какие проблемы сопряжены с попыткой сохранить полученную с первым сообщением часть данных?» Ответ такой: овчинка не стоит выделки. Тому есть ряд причин:

• обмен сообщениями (операции копирования на уровне ядра) выполняется очень быстро;

• проверка, получены ли данные целиком или частично, влечет определенные накладные расходы;

• дополнительные накладные расходы связаны с попыткой «сохранения» первой, уже прибывшей, части данных, в свете того факта, что ожидаются дополнительные.

По-моему, первые два пункта говорят сами за себя. Третий же пункт заслуживает пояснения. Давайте предположим, что клиент переслал большую порцию данных, и мы приняли-таки решение о том,

что было бы неплохо попробовать сохранить ту часть данных, которая уже получена. К сожалению, эта часть оказалось очень небольшой. Это означает, что вместо одного непрерывного массива байт у нас теперь будет большой кусок и маленький «довесок». Иными словами, только ради этого маленького кусочка нам придется значительно усложнять работу с данными, что может неприятно сказаться на эффективности кода. Это потенциальная головная боль, не делайте так!

Реальным ответом на поставленный вопрос будет просто заново считать данные в заранее подготовленные буферы. В нашем простом примере функции io_write я буду просто каждый раз выделять буфер при помощи malloc, считывать в него данные, а затем освобождать его функцией free. Разумеется, есть и куда более эффективные способы выделения буферов и управления ими!

Еще один тонкий момент в этом примере функции io_write — это обработка модификатора _IO_XTYPE_OFFSET (и связанных с этим данных; здесь она выполняется несколько иначе, чем в примере io_read).

/*

 * io_write1.c

*/

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <sys/neutrino.h>

#include <sys/iofunc.h>

void process_data(int offset, void *buffer, int nbytes) {

 // Сделать что-нибудь с данными

}

int io_write(resmgr_context_t *ctp, io_write_t *msg,

 iofunc_ocb_t *ocb) {

 int sts;

 int nbytes;

 int off;

 int start_data_offset;

 int xtype;

 char *buffer;

 struct _xtype_offset *xoffset;

 // Проверить, открыто ли устройство на запись

 if ((sts =

iofunc_write_verify(ctp, msg, ocb, NULL)) != EOK) {

return (sts);

 }

 // 1) Проверить и обработать переопределение

 XTYPE xtype = msg->i.xtype & _IO_XTYPE_MASK;

 if (xtype == _IO_XTYPE_OFFSET) {

xoffset = (struct _xtype_offset*)(&msg->i + 1);

start_data_offset = sizeof(msg->i) + sizeof(*xoffset);

off = xoffset->offset;

 } else if (xtype == _IO_XTYPE_NONE) {

off = ocb->offset;

start_data_offset = sizeof(msg->i);

 } else {

// Неизвестный тип; игнорировать

return (ENOSYS);

 }

 // 2) Выделить достаточно большой буфер для данных

 nbytes = msg->i.nbytes;

 if ((buffer = malloc(nbytes)) == NULL) {

return (ENOMEM);

 }

 // 3) Считать данные от клиента (возможно, повторно)

Поделиться:
Популярные книги

На границе империй. Том 6

INDIGO
6. Фортуна дама переменчивая
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
5.31
рейтинг книги
На границе империй. Том 6

Возмездие

Злобин Михаил
4. О чем молчат могилы
Фантастика:
фэнтези
7.47
рейтинг книги
Возмездие

Маяк надежды

Кас Маркус
5. Артефактор
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Маяк надежды

Невеста

Вудворт Франциска
Любовные романы:
любовно-фантастические романы
эро литература
8.54
рейтинг книги
Невеста

Кодекс Охотника. Книга XVIII

Винокуров Юрий
18. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга XVIII

Береги честь смолоду

Вяч Павел
1. Порог Хирург
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Береги честь смолоду

Соль этого лета

Рам Янка
1. Самбисты
Любовные романы:
современные любовные романы
6.00
рейтинг книги
Соль этого лета

Неправильный лекарь. Том 1

Измайлов Сергей
1. Неправильный лекарь
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Неправильный лекарь. Том 1

Бастард Императора. Том 5

Орлов Андрей Юрьевич
5. Бастард Императора
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 5

Попаданка в семье драконов

Свадьбина Любовь
Попаданка в академии драконов
Любовные романы:
любовно-фантастические романы
7.37
рейтинг книги
Попаданка в семье драконов

Идеальный мир для Лекаря 25

Сапфир Олег
25. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 25

Я не Монте-Кристо

Тоцка Тала
Любовные романы:
современные любовные романы
5.57
рейтинг книги
Я не Монте-Кристо

Довлатов. Сонный лекарь 3

Голд Джон
3. Не вывожу
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Довлатов. Сонный лекарь 3

Неудержимый. Книга XIII

Боярский Андрей
13. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Неудержимый. Книга XIII