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

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

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Роб Кёртен, "Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform" бесплатно, без регистрации.
Перейти на страницу:

struct _io_connect_link_reply {

 uint32_t reserved1[2];

 uint8_t  eflag;

 uint8_t  reserved2[3];

 uint32_t umask;

 uint16_t nentries;

 uint16_t path_len;

};


typedef union {

 struct _io_connect            connect;

 struct _io_connect_link_reply link_reply;

} io_unlink_t;

Описание: Отвечает за уничтожение связей (unlinking) файла, имя пути которого передается в поле path структуры входящего сообщения.

Возвращает: Состояние по применению вспомогательного макроса _RESMGR_STATUS.

io_unlock_ocb()

int io_unlock_ocb(resmgr_context_t *ctp, void *reserved,

 RESMGR_OCB_T *ocb)

Классификация: Функция ввода/вывода (синтезируется библиотекой)

Обработчик по умолчанию: iofunc_unlock_ocb_default()

Вспомогательные функции: Нет

Клиентская функция: Все

Сообщения: Нет (синтезируется библиотекой)

Структура данных: Нет

Описание: Действует противоположно вышеописанной функции io_lock_ocb(), т.е. отвечает за разблокирование атрибутной записи, на которую указывает OCB. Эта операция освобождает атрибутную запись, чтобы другие администратора ресурсов могли с ней работать. Подробности см. выше в разделе «Составные сообщения».

Возвращает: Код завершения, при помощи вспомогательного макроса _RESMGR_STATUS.

io_utime()

int io_utime(resmgr_context_t *ctp, io_utime_t *msg,

 RESMGR_OCB_T *ocb)

Классификация: Функция ввода/вывода

Обработчик по умолчанию: iofunc_utime_default()

Вспомогательные функции: iofunc_utime()

Клиентская функция: utime()

Сообщения: _IO_UTIME

Структура данных:

struct _io_utime {

 uint16_t       type;

 uint16_t       combine_len;

 int32_t        cur_flag;

 struct utimbuf times;

};


typedef union {

 struct _io_utime i;

} io_utime_t;

Описание: Устанавливает времена последнего доступа и модификации либо в «текущий момент» (если они равны нулю), либо в заданные значения. Заметьте, что согласно правилам POSIX этот обработчик сообщения может быть необходим для модификации флагов IOFUNC_ATTR_* в атрибутной записи. Вам почти никогда не придется самостоятельно использовать этот обработчик; вместо этого вы будете использовать вспомогательную функцию POSIX-уровня.

Возвращает: Код завершения, при помощи вспомогательного макроса _RESMGR_STATUS.

io_write()

int io_write(resmgr_context_t *ctp, io_write_t *msg,

 RESMGR_OCB_T *ocb)

Классификация: Функция ввода/вывода

Обработчик по умолчанию: iofunc_write_default()

Вспомогательные функции: iofunc_write_verify()

Клиентская функция: 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 <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, как это было описано в главе «Процессы и потоки» в обсуждениях функций пула потоков.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*