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

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

Жанры

Введение в 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) Считать данные от клиента (возможно, повторно)

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

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

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

Законы Рода. Том 6

Flow Ascold
6. Граф Берестьев
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 6

На границе империй. Том 10. Часть 1

INDIGO
Вселенная EVE Online
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 10. Часть 1

Черный Маг Императора 9

Герда Александр
9. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 9

Пожиратели миров 2

Кири Кирико
2. Сердце реальности
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Пожиратели миров 2

Аромат невинности

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

Доктора вызывали? или Трудовые будни попаданки

Марей Соня
Фантастика:
юмористическая фантастика
попаданцы
5.00
рейтинг книги
Доктора вызывали? или Трудовые будни попаданки

Подаренная чёрному дракону

Лунёва Мария
Любовные романы:
любовно-фантастические романы
7.07
рейтинг книги
Подаренная чёрному дракону

Князь

Шмаков Алексей Семенович
5. Светлая Тьма
Фантастика:
юмористическое фэнтези
городское фэнтези
аниме
сказочная фантастика
5.00
рейтинг книги
Князь

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

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

Я – Стрела. Трилогия

Суббота Светлана
Я - Стрела
Любовные романы:
любовно-фантастические романы
эро литература
6.82
рейтинг книги
Я – Стрела. Трилогия

Законы Рода. Том 4

Flow Ascold
4. Граф Берестьев
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 4

Последний рейд

Сай Ярослав
5. Медорфенов
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Последний рейд

Помещица Бедная Лиза

Шах Ольга
Любовные романы:
любовно-фантастические романы
6.40
рейтинг книги
Помещица Бедная Лиза