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

ЖАНРЫ

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

Кёртен Роб

Шрифт:

• функции пула потоков (мы обсуждали их в главе «Процессы и потоки», в параграфе «Пулы потоков»);

• интерфейс диспетчеризации;

• функции администратора ресурсов;

• вспомогательные функции POSIX-библиотеки.

При том, что можно было бы, конечно, писать администраторы ресурсов «с нуля» (как это делалось в QNX4), эта овчинка часто не стоит такой выделки.

Просто для демонстрации практичности библиотечного подхода — вот код однопоточной версии администратора «

/dev/null
»:

/*

 * resmgr1.c

 *

 * /dev/null
на основе библиотеки администратора ресурсов

*/

#include <stdio.h>

#include <stdlib.h>

#include <stddef.h>

#include <sys/iofunc.h>

#include <sys/dispatch.h>

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– то и привязывает их к двум передаваемым ей таблицам.

resmgr_attach

Создает канал, который администратор ресурса будет использовать для приема сообщений, и говорит администратору процессов, что мы намерены отвечать за «

/dev/null
». Параметров тут много, но к этой головной боли мы вернемся несколько позже. Сейчас же важно отметить, что именно здесь связываются воедино дескриптор диспетчера (dpp), имя пути (строка «
/dev/null
») и обработчики функций установления соединения (cfuncs) и ввода/вывода (ifuncs).

resmgr_context_alloc

Выделяет внутренний контекстный блок администратора ресурса. Мы рассмотрим этот блок в подробностях несколько позже, а вкратце — он содержит информацию, относящуюся к обрабатываемому сообщению.

resmgr_block

Это блокирующий вызов администратора ресурса — функция, с помощью которой мы ожидаем сообщение от клиента.

resmgr_handler

После того как сообщение от клиента получено, для его обработки вызывается эта функция.

За кулисами библиотеки

Вы уже видели, что наша программа ответственна за предоставление основного рабочего цикла приема сообщений:

while (1) {

 // Здесь ждем сообщения

 if ((ctp = resmgr_block(ctp)) == NULL) {

perror("Unable to resmgr_block\n");

exit(EXIT_FAILURE);

 }

 // Обработать сообщение

 resmgr_handler(ctp);

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