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

ЖАНРЫ

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

Кёртен Роб

Шрифт:
Поддерживание контекстной информации

И «учет размеров областей данных», и «обработка EOF» требуют, чтобы в OCB, передаваемом вашей функции io_read, поддерживалась контекстная информация — в частности, поле offset.

Обновление информации POSIX

И еще одно заключительное соображение: при чтении данных из ресурса должна обновляться POSIX-переменная времени доступа atime («access time» — «время доступа»). Это делается для того, чтобы клиентская функция stat могла обнаружить, что к устройству кто-то обращался.

Собственно код

Ниже приведена программа, в которой учтены

все вышеперечисленные моменты. Ниже мы ее последовательно проанализируем.

/*

 * io.read1.c

*/

#include <stdio.h>

#include <errno.h>

#include <sys/neutrino.h>

#include <sys/iofunc.h>

// наша строка с данными

char* data_string = "Здравствуй, мир!\n";

int io_read(resmgr_context_t* ctp, io_read_t* msg,

 iofunc_ocb_t* ocb) {

 int sts;

 int nbytes;

 int nleft;

 int off;

 int xtype;

 struct _xtype_offset* xoffset;

 // 1) Проверить, открыто ли устройство на чтение

 if ((sts ==

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

return sts;

 }

 // 2) проверить и обработать переопределение XTYPE

 xtype = msg->i.xtype & _IO_XTYPE_MASK;

 if (xtype == _IO_XTYPE_OFFSET) {

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

off = xoffset->offset;

 } else if (xtype = _IO_XTYPE_NONE) {

off = ocb->offset;

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

return ENOSYS;

 }

 // 3) Сколько байт осталось?

 nleft = ocb->attr->nbytes – off;

 // 4) Сколько байт мы можем отдать клиенту?

 nbytes = min(nleft, msg->i.nbytes);

 // 5) Если возвращаем данные, отдать их клиенту

 if (nbytes) {

MsgReply(ctp->rcvid, nbytes, data_string+off, nbytes);

// 6) Установить значение "atime" для POSIX stat

ocb->attr->flags |=

IOFUNC_ATTR_ATIME | IOFUNC_ATTR_DIRTY_TIME;

// 7) Если индекс lseek не равен _IO_XTYPE_OFFSET,

// увеличить его на число считанных байт

if (xtype == _IO_XTYPE_NONE) {

ocb->offset += nbytes;

}

 } else {

// 8) Не возвращаем данные, просто разблокировать клиента

MsgReply(ctp->rcvid, EOK, null, 0);

 }

 // 9) Сказать библиотеке, что мы уже ответили сами

 return _RESMGR_NOREPLY;

}

Этап 1

Здесь

мы убедились, что клиентский вызов open действительно запросил открытие устройства на чтение. Если бы клиент открыл устройство только на запись, а затем попытался выполнить чтение, это следовало бы расценивать как ошибку. В этом случае вспомогательная функция iofunc_read_verify возвратила бы нам (затем мы — библиотеке, а библиотека — клиенту) EBADF, а не EOK.

Этап 2

Здесь мы проверили, указал ли клиент индивидуальное для данного сообщения переопределение типа (xtype-override) (например, потому что если мы открыли устройство в неблокирующем режиме, то это указало бы, что для данного конкретного запроса мы хотим задать блокирующее поведение). Отметим, что блокирующий аспект переопределенияа типа может быть отражён в последнем параметре функции iofunc_read_verify, однако, поскольку мы приводим здесь упрощенный пример, мы передаем NULL, указывая этим, что этот вопрос нас не волнует.

Более важно, однако, посмотреть, как обрабатываются конкретные модификаторы xtype. Очень интересен, например, модификатор _IO_XTYPE_OFFSET, который, если присутствует, указывает на то, что принятое от клиента сообщение содержит смещение, и что операция чтения не должна изменять «текущую позицию файла» для данного файлового дескриптора (так делает, например, функция pread). Если модификатор _IO_XTYPE_OFFSET не указан, то операция чтения может смело модифицировать «текущую позицию файла». Мы используем переменную хtype для сохранения xtype, содержавшегося в принятом сообщении, и переменную off для представления текущего смещения, которое мы должны будем использовать при обработке. Далее, на этапе 7, вы увидите еще кое-какие действия по обработке модификатора _IO_XTYPE_OFFSET.

Если присутствует иное переопределение xtype, чем _IO_XTYPE_OFFSET (и это не пустая команда _IO_XTYPE_NONE), мы отказываемся обрабатывать запрос и возвращаем ENOSYS. Это просто означает, что мы не знаем, как обрабатывать такую ситуацию, и поэтому возвращаем клиенту признак ошибки.

Этапы 3 и 4

Чтобы вычислить, сколько байт мы можем реально возвратить клиенту, мы выполняем этапы 3 и 4, в которых выясняется, сколько байт доступно у устройства (разность между полным объемом устройства, полученным из

ocb->attr->nbytes
, и текущим смещением в устройстве). Узнав, сколько байт осталось, мы выбираем наименьшее значение между размером этого остатка и количеством байт, которые клиент хочет прочитать. Например, у нас может остаться семь байт, а клиент захочет прочитать только два. В этом случае мы возвратим клиенту только два байта. И наоборот, если клиент захочет прочитать 4096 байт, а у нас осталось только семь, мы сможем возвратить ему только семь байт.

Этап 5

Теперь, вычислив, сколько байт мы намерены возвратить клиенту, нам нужно сделать ряд вещей в зависимости от того, возвращаем мы данные или нет. Если да, то мы просто отвечаем клиенту с данными сразу после проверки на этапе 5. Обратите внимание, что для возврата данных с корректного смещения мы используем

data_string + off
(смещение off вычисляется в зависимости от наличия переопределения типа). Отметьте также второй параметр функции MsgReply — в документации он упоминается как «status» («код завершения»), но в этом случае мы используем его для возврата числа байт. Мы делаем так, потому что реализация клиентской функции read знает, что значение, возвращаемое ее функцией MsgSendv (а это, кстати, как раз и есть параметр status функции MsgReply) представляет собой число реально прочитанных байт — это общеизвестное соглашение.

Поделиться с друзьями: