Вспомогательные функции: Нет
Клиентская функция: Все
Сообщения: Нет (синтезируется библиотекой)
Структура данных: Нет
Описание: Действует противоположно вышеописанной функции io_lock_ocb(), т.е. отвечает за разблокирование атрибутной записи, на которую указывает OCB. Эта операция освобождает атрибутную запись, чтобы другие администратора ресурсов могли с ней работать. Подробности см. выше в разделе «Составные сообщения».
Возвращает: Код завершения, при помощи вспомогательного макроса _RESMGR_STATUS.
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.
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;