Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
- Название:Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
- Автор:
- Жанр:
- Издательство:Петрополис
- Год:2001
- Город:Санкт-Петербург
- ISBN:5-94656-025-9
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform краткое содержание
Книга "Введение в QNX/Neutrino 2» откроет перед вами в мельчайших подробностях все секреты ОСРВ нового поколения от компании QNX Software Systems Ltd (QSSL) — QNX/Neutrino 2. Книга написана в непринужденной манере, легким для чтения и понимания стилем, и поможет любому, от начинающих программистов до опытных системотехников, получить необходимые начальные знания для проектирования надежных систем реального времени, от встраиваемых управляющих приложений до распределенных сетевых вычислительных систем
В книге подробно описаны основные составляющие ОС QNX/Neutrino и их взаимосвязи. В частности, уделено особое внимание следующим темам:
• обмен сообщениями: принципы функционирования и основы применения;
• процессы и потоки: базовые концепции, предостережения и рекомендации;
• таймеры: организация периодических событий в программах;
• администраторы ресурсов: все, что относится к программированию драйверов устройств;
• прерывания: рекомендации по эффективной обработке.
В книге представлено множество проверенных примеров кода, подробных разъяснений и рисунков, которые помогут вам детально вникнуть в и излагаемый материал. Примеры кода и обновления к ним также можно найти на веб-сайте автора данной книги, www.parse.com.
Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Клиентская функция: write() , fwrite() , и т.п.
Сообщения: _IO_WRITE
Структура данных:
struct _io_write {
uint16_t type ;
uint16_t combine_len ;
int32_t nbytes ;
uint32_t xtype ;
};
typedef union {
struct _io_write i ;
} io_write_t;
Описание: Данный обработчик отвечает за получение данных, которые клиент записал в администратор ресурсов. Обработчику передается число байт, которые клиент пытается записать, в элементе nbytes ; данные неявно следуют за входной структурой (если параметр xtype не установлен в _IO_XTYPE_OFFSET; см. ниже параграф «Простой пример функции io_write() »!). Согласно реализации, потребуется повторное считывание от клиента части сообщения с данными при помощи функции resmgr_msgreadv() или ей эквивалентной. Код завершения дает число байт, фактически записанных, либо устанавливает признак ошибки в errno .
Отметьте, что чтобы удостовериться, что файл был открыт в режиме, совместимом с записью, следует вызвать вспомогательную функцию iofunc_write_verify() . Также следует вызывать функцию iofunc_sync_verify() для проверки необходимости синхронизации данных с носителем.
Возвращает: Код завершения, при помощи вспомогательного макроса _IO_SET_WRITE_NBYTES .
Пример см. ниже в параграфе «Простой пример функции io_write() ».
Примеры
Этот раздел — своего рода «кулинарная книга» для программистов. Здесь я приведу ряд готовых примеров, которые вы сможете непосредственно использовать в качестве базиса для ваших проектов. Это не совсем готовые администраторы ресурсов — вы должны будете дополнить их функциями работы с пулами потоков и «каркасом» диспетчеризации (о котором речь ниже), а также удостовериться, что ваши версии функций- обработчиков помещаются в соответствующие таблицы функций после вызова iofunc_func_init() , чтобы корректно переопределить значения по умолчанию!
Я начну с ряда простых примеров, демонстрирующих базовые функциональные возможности обработчиков различных сообщений, таких как:
• io_read()
• io_write()
• io_devctl() (без передачи данных)
• io_devctl() (с передачей данных)
Затем, в разделе «Дополнительно», мы рассмотрим обработчик io_read() , который обеспечивает возврат элементов каталога.
Приведенный ниже пример можно использовать в качестве шаблона для многопоточного администратора ресурсов. (Шаблон однопоточного администратора ресурсов мы уже рассматривали — это было в разделе «Библиотека администратора ресурсов», когда мы обсуждали администратор /dev/null
).
#include
#include
#include
#include
#include
static resmgr_connect_funcs_t connect_func;
static resmgr_io_funcs_t io_func;
static iofunc_attr_t attr;
main(int argc, char **argv) {
thread_pool_attr_t pool_attr;
thread_pool_t *tpp;
dispatch_t *dpp;
resmgr_attr_t resmgr_attr;
resmgr_context_t *ctp;
int id;
if ((dpp = dispatch_create()) == NULL) {
fprintf(stderr,
"%s: Ошибка выделения контекста диспетчеризации\n",
argv[0]);
return (EXIT_FAILURE);
}
memset(&pool_attr, 0, sizeof(pool_attr));
pool_attr.handle = dpp;
pool_attr.context_alloc = resmgr_context_alloc;
pool_attr.block_func = resmgr_block;
pool_attr.handler_func = resmgr_handler;
pool_attr.context_free = resmgr_context_free;
// 1) Настроить пул потоков
pool_attr.lo_water = 2;
pool_attr.hi_water = 4;
pool_attr.increment = 1;
pool_attr.maximum = 50;
if ((tpp =
thread_pool_create(&pool_attr, POOL_FLAG_EXIT_SELF))
== NULL) {
fprintf(stderr,
"%s: Ошибка инициализации пула потоков\n",
argv[0]);
return (EXIT_FAILURE);
}
iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &connect_func,
_RESMGR_IO_NFUNCS, &io_func);
iofunc_attr_init(&attr, S_IFNAM | 0777, 0, 0);
// 2) Переопределить функции установления соединения
// и функции ввода/вывода, как надо
memset(&resmgr_attr, 0, sizeof(resmgr_attr));
resmgr_attr.nparts_max = 1;
resmgr_attr.msg_max_size = 2048;
// 3) Замените «/dev/whatever» на нужный префикс
if ((id =
resmgr_attach(dpp, &resmgr_attr, "/dev/whatever",
_FTYPE_ANY,
0, &connect_func, &io_func, &attr)) == -1) {
fprintf(stderr, "%s: Ошибка регистрации префикса\n",
argv[0]);
return (EXIT_FAILURE);
}
// Отсюда возврата не будет
thread_pool_start(tpp);
}
Дополнительную информацию об интерфейсе диспетчеризации (т.е., о функции dispatch_create() ), см. в справочном руководстве по Си-библиотеке (С Library Reference).
Здесь мы используем функции пула потоков для создания пула, который должен будет обслуживать сообщения в нашем администраторе ресурсов. Вообще говоря, я бы рекомендовал вам начать однопоточного администратора ресурсов, как мы это делали ранее в примере с администратором /dev/null
. Как только базовая функциональность у вас заработает, вы сможете затем добавить многопоточность. Вам нужно будет задать параметры lo_water , hi_water , increment и maximum структуры pool_attr , как это было описано в главе «Процессы и потоки» в обсуждениях функций пула потоков.
Здесь мы дополняем администратор ресурсов нашими функциями. Эти функции представляют собой функции- обработчики сообщений, о которых мы только что говорили (например, io_read() , io_devctl() , и т.п.). Например, чтобы добавить свой собственный обработчиком для сообщения _IO_READ, указывающий на функцию my_io_read() , мы должны были бы добавить в программу такую строчку:
io_func.io_read = my_io_read;
Это переопределит элемент таблицы, инициализированный вызовом iofunc_func_init() и содержавший функцию POSIX-уровня по умолчанию, заменив его указателем на вашу функцию my_io_read() .
Вы, вероятно, не захотите, чтобы ваш администратор ресурсов назывался /dev/whatever
(букв. — « /dev/абы_что
» — прим. ред .), так что вам придется выбрать для него соответствующее имя. Отметим, что привязка атрибутной записи (параметр attr ) к регистрируемому префиксу осуществляется вызовом resmgr_attach() — если бы нам было надо, чтобы наш администратор обрабатывал несколько устройств, нам пришлось бы вызывать resmgr_attach() несколько раз, каждый раз с новой атрибутной записью, чтобы на этапе выполнения можно было отличить зарегистрированные префиксы друг от друга.
Простой пример функции io_read()
Чтобы проиллюстрировать, как ваш администратор ресурса мог бы возвращать клиенту данные, рассмотрим простейший администратор ресурса, который всегда возвращает одну и ту же строковую константу « Здравствуй, мир!\n
». Даже в таком простом случае необходимо учесть ряд моментов, как-то:
Интервал:
Закладка: