MyBooks.club
Все категории

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

На сайте mybooks.club вы можете бесплатно читать книги онлайн без регистрации, включая Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform. Жанр: Программное обеспечение издательство -,. Доступна полная версия книги с кратким содержанием для предварительного ознакомления, аннотацией (предисловием), рецензиями от других читателей и их экспертным мнением.
Кроме того, на сайте mybooks.club вы найдете множество новинок, которые стоит прочитать.

Название:
Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
Автор
Издательство:
-
ISBN:
-
Год:
-
Дата добавления:
16 сентябрь 2019
Количество просмотров:
351
Читать онлайн
Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform

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

Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform - описание и краткое содержание, автор Роб Кёртен, читайте бесплатно онлайн на сайте электронной библиотеки mybooks.club
Книга "Введение в QNX/Neutrino 2» откроет перед вами в мельчайших подробностях все секреты ОСРВ нового поколения от компании QNX Software Systems Ltd (QSSL) — QNX/Neutrino 2. Книга написана в непринужденной манере, легким для чтения и понимания стилем, и поможет любому, от начинающих программистов до опытных системотехников, получить необходимые начальные знания для проектирования надежных систем реального времени, от встраиваемых управляющих приложений до распределенных сетевых вычислительных системВ книге подробно описаны основные составляющие ОС QNX/Neutrino и их взаимосвязи. В частности, уделено особое внимание следующим темам:• обмен сообщениями: принципы функционирования и основы применения;• процессы и потоки: базовые концепции, предостережения и рекомендации;• таймеры: организация периодических событий в программах;• администраторы ресурсов: все, что относится к программированию драйверов устройств;• прерывания: рекомендации по эффективной обработке.В книге представлено множество проверенных примеров кода, подробных разъяснений и рисунков, которые помогут вам детально вникнуть в и излагаемый материал. Примеры кода и обновления к ним также можно найти на веб-сайте автора данной книги, www.parse.com.

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

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

Теперь о наиболее важной особенности. Обратите внимание, как мы использовали для выполнения всей нашей работы функции POSIX-уровня по умолчанию! Функция iofunc_open_default() обычно размещается в таблице функций установления соединения в той же самой ячейке, которую сейчас занимает наша функция my_open(). Это означает, что они принимают одинаковый набор аргументов!

Все, что мы должны сделать — это решить, какую атрибутную запись мы хотим связать с OCB, создаваемым функцией по умолчанию: либо каталоговую (в этом случае мы передаем attr), либо одну из 26 имеющихся у нас файловых (тогда мы передаем соответствующий элемент atoz_attrs). Это ключевой момент, поскольку обработчик, который вы помещаете в слот open в таблице функций установления соединения, действует как «швейцар» по отношению ко всем последующим запросам к вашему администратору ресурса.

static int my_open(resmgr_context_t *ctp, io_open_t *msg,

 iofunc_attr_t *attr, void *extra) {

 if (msg->connect.path[0] == 0) {

  // Каталог (/dev/atoz)

  return (iofunc_open_default(ctp, msg, attr, extra));

 } else if (msg->connect.path[1] == 0 &&

  (msg->connect.path[0] >= 'a' &&

  msg->connect.path[0] <= 'z')) { // Файл (/dev/atoz/[a-z])

  return

   (iofunc_open_default(ctp, msg, atoz_attrs +

    msg->connect.path[0] - 'a', extra));

 } else {

  return (ENOENT);

 }

}

my_read()

В функции my_read(), чтобы решить, какие операции надо выполнить, мы анализируем поле mode атрибутной записи. Если макрос S_ISDIR() говорит, что это каталог, мы вызываем функцию my_read_dir(); если макрос S_ISREG() говорит, что это файл, мы вызываем функцию my_read_file(). (Отметим, что если мы не можем разобрать, что это такое, мы возвращаем клиенту EBADF, указывая ему этим, что что-то здесь не так.)

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

static int my_read(resmgr_context_t *ctp, io_read_t *msg,

 iofunc_ocb_t *ocb) {

 int sts;


 // Использовать вспомогательную функцию для проверки

 // корректности

 if ((sts =

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

   return (sts);

 }


 // Решить, надо ли читать «файл» или «каталог»

 if (S_ISDIR(ocb->attr->mode)) {

  return (my_read_dir(ctp, msg, ocb));

 } else if (S_ISREG(ocb->attr->mode)) {

  return (my_read_file(ctp, msg, ocb));

 } else {

  return (EBADF);

 }

}

my_read_dir()

Вот тут-то все веселье и начинается. С точки зрения высокого уровня, мы выделяем буфер (он называется reply_msg), в котором собираемся разместить результат операции. Затем мы используем dp, чтобы «прогуляться» по буферу, заполняя его по ходу дела элементами struct dirent. Вспомогательная подпрограмма dirent_size() применяется, чтобы определить, есть ли у нас место в буфере для еще одного элемента. Вспомогательная подпрограмма dirent_fill() кладет элемент в буфер. (Отметим, что эти подпрограммы не входят в библиотеку администратора ресурсов; мы обсудим их ниже.)

На первый взгляд этот код может показаться неэффективным; мы используем функцию sprintf() для создания двухбайтового имени файла (символ имени файла и признак конца строки NULL) в буфере длиной _POSIX_PATH_MAX (то есть 256) байт. Это делается для того, чтобы сделать код по возможности универсальным.

Наконец, обратите внимание, что мы используем поле offset в OCB для указания, для какого конкретного файла мы в данный момент генерируем структуру struct dirent. Это означает, что мы также должны корректировать поле offset всякий раз, когда возвращаем данные.

Возврат данных клиенту осуществляется «обычным» способом при помощи функции MsgReply(). Заметьте, что поле состояния (status) функции MsgReply() используется для указания числа отправленных клиенту байт.

static int my_read_dir(resmgr_context_t *ctp,

 io_read_t *msg, iofunc_ocb_t *ocb) {

 int nbytes;

 int nleft;

 struct dirent *dp;

 char *reply_msg;

 char fname[_POSIX_PATH_MAX];

 // Выделить буфер для ответа

 reply_msg = calloc(1, msg->i.nbytes);

 if (reply_msg == NULL) {

  return (ENOMEM);

 }


 // Назначить выходной буфер

 dp = (struct dirent *)reply_msg;


 // Осталось «nleft» байт

 nleft = msg->i.nbytes;

 while (ocb->offset < NUM_ENTS) {

  // Создать имя файла

  sprintf(fname, "%с", ocb->offset + "a");

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

  nbytes = dirent_size(fname);

  // Есть место?

  if (nleft - nbytes >= 0) {

   // Заполнить элемент каталога и увеличить указатель

   dp =

    dirent_fill(dp, ocb->offset + 1, ocb->offset, fname);

   // Увеличить смещение OCB

   ocb->offset++;

   // Учесть, сколько байт мы использовали

   nleft -= nbytes;

  } else {

   // Места больше нет, остановиться

   break;

  }

 }


 // Возвращаемся обратно к клиенту

 MsgReply(ctp->rcvid, (char*)dp - reply_msg, reply_msg,

  (char*)dp — reply_msg);


 // Освободить буфер

 free(reply_msg);

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

 return (_RESMGR_NOREPLY);

}

my_read_file()

В функции my_read_file() мы видим код, почти аналогичный простому примеру функции чтения, который приведен выше в данном разделе. Единственная странная вещь, которую мы здесь делаем — поскольку мы знаем, что возвращается всегда только один байт данных, значит, если параметр nbytes не равен нулю, то он должен быть равен единице (и ничему другому). Таким образом, мы можем создавать данные, подлежащие возврату, непосредственным заполнением символьной переменной string. Обратите внимание, как мы используем поле inode атрибутной записи для определения, какие данные возвращать. Это обычный прием для администраторов, обслуживающих несколько ресурсов. Дополнительным трюком было бы расширить атрибутную запись (мы говорили об этом в разделе «Расширение атрибутной записи») и хранить непосредственно в ней либо сами данные, либо указатель на них.

static int my_read_file(resmgr_context_t *ctp,

 io_read_t *msg, iofunc_ocb_t *ocb) {

 int nbytes;

 int nleft;

 char string;


 // Тут нет никаких xtype...

 if ((msg->i.xtype & _IO_XTYPE_MASK) != _IO_XTYPE_NONE) (

  return (ENOSYS);

 }


 // Выяснить, сколько байт осталось...

 nleft = ocb->attr->nbytes — ocb->offset;


 // ...и сколько мы можем возвратить клиенту

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

 if (nbytes) {

  // Создать ответную строку

  string = ocb->attr->inode - 1 + "A";

  // Возвратить ее клиенту

  MsgReply(ctp->rcvid, nbytes, &string + ocb->offset,

   nbytes);

  // Обновить флаги и смещение

  ocb->attr->flags |=

   IOFUNC_ATTR_ATIME | IOFUNC_ATTR_DIRTY_TIME;

  ocb->offset += nbytes;

 } else {

  // Возвращать нечего, индицировать конец файла

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

 }


 // Уже ответили сами

 return (_RESMGR_NOREPLY);

}

dirent_size()

Вспомогательная подпрограмма dirent_size() просто вычисляет число байт, необходимое для структуры struct dirent, с учетом ограничений по выравниванию. Опять же, для нашего простого администратора ресурсов здесь имеет место небольшое искусственное упрощение, потому что мы точно знаем, каков размер каждого элемента каталога — все имена файлов имеют длину ровно один байт. Однако, как бы там ни было, это все равно полезная служебная подпрограмма.

int dirent_size(char *fname) {

return (ALIGN(sizeof(struct dirent) - 4 + strlen(fname)));

}

dirent_fill()

И, наконец, вспомогательная подпрограмма dirent_fill() применяется для помещения передаваемых ей значений (а именно — полей inode, offset и fname) в также передаваемый ей элемент каталога. В порядке щедрости она также возвращает указатель на адрес (с учетом выравнивания), с которого должен начинаться следующий элемент каталога.

struct dirent* dirent_fill(struct dirent *dp, int inode,

 int offset, char *fname) {

 dp->d_ino = inode;

 dp->d_offset = offset;


Роб Кёртен читать все книги автора по порядку

Роб Кёртен - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки mybooks.club.


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

Отзывы читателей о книге Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform, автор: Роб Кёртен. Читайте комментарии и мнения людей о произведении.

Прокомментировать
Подтвердите что вы не робот:*
Подтвердите что вы не робот:*
Все материалы на сайте размещаются его пользователями.
Администратор сайта не несёт ответственности за действия пользователей сайта..
Вы можете направить вашу жалобу на почту librarybook.ru@gmail.com или заполнить форму обратной связи.