Роб Кёртен - Введение в 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 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
fp = fopen("/dev/multiport/57", "w");
Администратор процессов разрешает это в четверку ND/PID/CHID/handle для мультипортового администратора; решать, насколько корректен при этом остаток имени («57») — это уже дело самого администратора ресурса. В этом примере, предположив, что часть имени пути после точки монтирования хранится в переменной path , администратор ресурса мог бы выполнить проверку очень простым способом:
devnum = atoi(path);
if ((devnum <= 0) || (devnum >= 256)) {
// Неправильный номер устройства
} else {
// Правильный номер устройства
}
Этот будет однозначно быстрее, чем поиск, выполняемый администратором процессов, — хотя бы потому что администратор процессов по сути своей намного более универсален, чем наш администратор ресурса.
Обработка сообщений
Как только мы зарегистрировали один или более префиксов, мы должны быть готовы принимать сообщения от клиентов. Это делается «обычным» способом с помощью функции MsgReceive() . Существуют менее 30 четко определенных типов сообщений, которые администратор ресурса должен быть способен обработать. Однако, для упрощения обсуждения и реализации их условно делят на две группы:
Сообщения установления соединения (connect messages)
Всегда содержат имя пути; либо являются однократными, либо устанавливают контекст для последующих сообщений ввода/вывода.
Сообщения ввода/вывода (I/O messages)
Всегда базируются на сообщениях установления соединения; выполняют всю последующую работу.
Сообщения установления соединения всегда содержат имя пути. Прекрасным примером функции, генерирующей сообщение установления соединения, является уже не раз упомянутая нами функция open() . В этом случае обработчик (handle) сообщения установления соединении устанавливает контекст для последующих сообщений ввода/вывода. (В конце-то концов, после open() мы все-таки собираемся делать что-то наподобие read() .).
Примером «однократного» сообщения установления соединения может быть сообщение, сгенерированное в результате вызова rename() . Здесь никакого контекста не предполагается — обработчик в администраторе ресурса изменяет имя указанного файла на новое, и все.
Сообщения ввода/вывода возникают только после соответствующего сообщения установления соединения и ссылаются на установленный им контекст. Как уже упоминалось ранее при обсуждении сообщений установления соединения, идеальный пример — вызов функции open() , за которым следует read() .
Кроме сообщений об установлении соединения и сообщений ввода/вывода, есть еще и «другие» сообщения, которые администратор ресурсов может принимать и обрабатывать. Но поскольку они не являются в полной мере «административными», покамест отложим их обсуждение и вернемся к ним позже.
Библиотека администратора ресурсов
Прежде чем лезть в глубины организации администраторов ресурсов, познакомимся сначала с библиотекой администратора ресурсов, разработанной QSSL. Отметим, что в действительности эта «библиотека» состоит из нескольких четко различимых частей:
• функции пула потоков (мы обсуждали их в главе «Процессы и потоки», в параграфе «Пулы потоков»);
• интерфейс диспетчеризации;
• функции администратора ресурсов;
• вспомогательные функции POSIX-библиотеки.
При том, что можно было бы, конечно, писать администраторы ресурсов «с нуля» (как это делалось в QNX4), эта овчинка часто не стоит такой выделки.
Просто для демонстрации практичности библиотечного подхода — вот код однопоточной версии администратора « /dev/null
»:
/*
* resmgr1.c
*
* /dev/null на основе библиотеки администратора ресурсов
*/
#include
#include
#include
#include
#include
int main(int argc, char **argv) {
dispatch_t *dpp;
resmgr_attr_t resmgr_attr;
resmgr_context_t *ctp;
resmgr_connect_funcs_t connect_func;
resmgr_io_funcs_t io_func;
iofunc_attr_t attr;
// Создать структуру диспетчеризации
if ((dpp = dispatch_create()) == NULL) {
perror("Ошибка dispatch_create\n");
exit(EXIT_FAILURE);
}
// Инициализировать структуры данных
memset(&resmgr_attr, 0, sizeof(resmgr_attr));
resmgr_attr.nparts_max = 1;
resmgr_attr.msg_max_size = 2048;
// Назначить вызовам обработчики по умолчанию
iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &connect_func,
_RESMGR_IO_NFUNCS, &io_func);
iofunc_attr_init(&attr, S_IFNAM | 0666, 0, 0);
// Зарегистрировать префикс в пространстве имен путей
if (resmgr_attach(dpp, &resmgr_attr,
"/dev/mynull", _FTYPE_ANY,
0, &connect_func, &io_func, &attr) == -1) {
perror("Ошибка resmgr_attach\n");
exit(EXIT_FAILURE);
}
ctp = resmgr_context_alloc(dpp);
// Ждать сообщений в вечном цикле
while (1) (
if ((ctp = resmgr_block(ctp)) == NULL) {
perror("Ошибка resmgr_block\n");
exit(EXIT_FAILURE);
}
resmgr_handler(ctp);
}
}
И все! Полнофункциональный администратор ресурса /dev/null
реализуется всего несколькими вызовами функций!
Если бы пришлось писать аналогичный по функциональности администратор (то есть с поддержкой функций stat() , chown() , chmod() , и т.д.) «с нуля», то вам пришлось бы перелопатить сотни, если не тысячи строк Си-кода.
Реально все это за вас делает библиотека
Как вариант начального знакомства с библиотекой, давайте посмотрим, что делают вызовы, использованные в администраторе ресурсов /dev/null
:
dispatch _create()
Создает структуру диспетчеризации; она будет использоваться для блокирования по приему сообщения.
iofunc_attr_init()
Инициализирует используемую устройством атрибутную запись. Мы обсудим атрибутные записи в подробностях несколько позже, а вкратце так: атрибутная запись содержит информацию об устройстве, и на каждое имя устройства имеется по одной атрибутной записи.
iofunc_func_init()
Инициализирует две структуры данных, cfuncs и ifuncs , которые содержат соответственно указатели на функции установления соединения и функции ввода/вывода. Это, пожалуй, самый «магический» вызов, поскольку именно он назначает подпрограммы обработки сообщений, привязывая их к структурам данных. Заметьте, что никакого кода обработки сообщений установления соединения или сообщений ввода/вывода, генерируемых функциями read() , stat() или им подобными, в администраторе нет. Дело в том, что библиотека содержит для всех сообщений готовые POSIX-обработчики по умолчанию, и как раз функция iofunc_func_init() -то и привязывает их к двум передаваемым ей таблицам.
Читать дальшеИнтервал:
Закладка: