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

Примеры

Этот раздел — своего рода «кулинарная книга» для программистов. Здесь я приведу ряд готовых примеров, которые вы сможете непосредственно использовать в качестве базиса для ваших проектов. Это не совсем готовые администраторы ресурсов — вы должны будете дополнить их функциями работы с пулами потоков и «каркасом» диспетчеризации (о котором речь ниже), а также удостовериться, что ваши версии функций- обработчиков помещаются в соответствующие таблицы функций после вызова iofunc_func_init(), чтобы корректно переопределить значения по умолчанию!

Я начну с ряда простых примеров, демонстрирующих базовые функциональные возможности обработчиков различных сообщений, таких как:

• io_read()

• io_write()

• io_devctl() (без передачи данных)

• io_devctl() (с передачей данных)

Затем, в разделе «Дополнительно», мы рассмотрим обработчик io_read(), который обеспечивает возврат элементов каталога.

Базовый каркас администратора ресурсов

Приведенный ниже пример можно использовать в качестве шаблона для многопоточного администратора ресурсов. (Шаблон однопоточного администратора ресурсов мы уже рассматривали — это было в разделе «Библиотека администратора ресурсов», когда мы обсуждали администратор /dev/null).

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <sys/iofunc.h>
#include <sys/dispatch.h>
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).

Этап 1

Здесь мы используем функции пула потоков для создания пула, который должен будет обслуживать сообщения в нашем администраторе ресурсов. Вообще говоря, я бы рекомендовал вам начать однопоточного администратора ресурсов, как мы это делали ранее в примере с администратором /dev/null. Как только базовая функциональность у вас заработает, вы сможете затем добавить многопоточность. Вам нужно будет задать параметры lo_water, hi_water, increment и maximum структуры pool_attr, как это было описано в главе «Процессы и потоки» в обсуждениях функций пула потоков.

Этап 2

Здесь мы дополняем администратор ресурсов нашими функциями. Эти функции представляют собой функции- обработчики сообщений, о которых мы только что говорили (например, io_read(), io_devctl(), и т.п.). Например, чтобы добавить свой собственный обработчиком для сообщения _IO_READ, указывающий на функцию my_io_read(), мы должны были бы добавить в программу такую строчку:

io_func.io_read = my_io_read;

Это переопределит элемент таблицы, инициализированный вызовом iofunc_func_init() и содержавший функцию POSIX-уровня по умолчанию, заменив его указателем на вашу функцию my_io_read().

Этап 3

Вы, вероятно, не захотите, чтобы ваш администратор ресурсов назывался /dev/whatever (букв. — «/dev/абы_что» — прим. ред.), так что вам придется выбрать для него соответствующее имя. Отметим, что привязка атрибутной записи (параметр attr) к регистрируемому префиксу осуществляется вызовом resmgr_attach() — если бы нам было надо, чтобы наш администратор обрабатывал несколько устройств, нам пришлось бы вызывать resmgr_attach() несколько раз, каждый раз с новой атрибутной записью, чтобы на этапе выполнения можно было отличить зарегистрированные префиксы друг от друга.

Оглавление книги


Генерация: 0.109. Запросов К БД/Cache: 0 / 0
поделиться
Вверх Вниз