int (*unlock_ocb)(ctp, void *reserved, ocb);
int (*sync)(ctp, io_sync_t *msg, ocb);
} resmgr_io_funcs_t;
В этой структуре я тоже сократил прототипы, опустив тип элемента ctp ( resmgr_context_t*
) и тип последнего элемента, ocb ( RESMGR_OCB_T*
). Полный прототип, например, для функции read() в действительности имеет вид:
int (*read)(resmgr_context_t * ctp , io_read_t * msg , RESMGR_OCB_T * ocb );
Самый первый элемент структуры ( nfuncs ) указывает, насколько она велика (то есть сколько элементов она содержит). Текущее значение этого элемента содержится в константе _RESMGR_IO_NFUNCS.
Отметим, что списки параметров в таблице функций ввода/вывода также довольно однообразны. Первый параметр — ctp , второй параметр — msg , как и у обработчиков из таблицы функций установления соединения.
Третий параметр, однако, отличается. Этот параметр называется ocb , что расшифровывается как «Open Context Block» — «блок открытого контекста». Этот блок содержит контекст, созданный обработчиком сообщения установления соединения (например, в результате клиентского запроса open() ) и доступный функциям ввода/вывода.
Как уже упоминалось ранее, когда придет время заполнять таблицы функций, рекомендуется пользоваться для этого функцией iofunc_func_init() , чтобы сначала загрузить таблицы POSIX-обработчиками по умолчанию. Если же вам будет нужно переопределить обработчики сообщений определенного типа, вы сможете просто заменить POSIX-обработчики по умолчанию на свои собственные. Мы рассмотрим это в разделе «Подстановка своих собственных функций».
Внутренний контекстный блок resmgr_context_t
И, наконец, еще одна структура данных используется базовым уровнем библиотеки, чтобы отслеживать кое-какую информацию для себя . Вам не следует изменять содержимое этой структуры, за исключением одного элемента — вектора ввода/вывода iov .
Вот эта структура данных (взято из ):
typedef struct _resmgr_context {
int rcvid ;
struct _msg_info info ;
resmgr_iomsgs_t * msg ;
struct _resmgr_ctrl * ctrl ;
int id ;
int status ;
int offset ;
int size ;
iov_t iov [1];
} resmgr_context_t;
Как и в случае с другими структурами данных, я позволил себе опустить зарезервированные поля.
Давайте взглянем на ее содержимое.
rcvid |
Идентификатор отправителя, полученный от MsgReceivev() . Указывает, кому вы должны ответить (если вы намерены отвечать самостоятельно). |
info |
Содержит информационную структуру, возвращаемую функцией MsgReceivev() в основном цикле приема сообщений библиотеки администратора ресурсов. Полезна для получения информации о клиенте, включая дескриптор узла, идентификатор процесса (PID), идентификатор потока и т.д. Подробнее см. документацию по функции MsgReceivev() . |
msg |
Указатель на объединение (union) всех возможных типов сообщений. Практически бесполезен, потому что каждая из ваших функций-обработчиков получает соответствующий элемент объединения вторым параметром. |
ctrl |
Указатель на управляющую структуру, которую вы передали в самом начале. Опять же, для вас этот параметр не очень полезен, но зато полезен для библиотеки администратора ресурсов. |
id |
Идентификатор точки монтирования, которой предназначалось сообщение. Когда вы вызывали resmgr_attach() , она вернула вам небольшой целочисленный идентификатор. Это и есть значение id . Отметим, что вы вероятнее всего никогда не будете использовать этот параметр самостоятельно, а будете полагаться вместо этого на атрибутную запись, передаваемую вам обработчиком io_open() . |
status |
Сюда ваша функция-обработчик помещает результат выполнения операции. Отметим, что вы должны всегда использовать макрос _RESMGR_STATUS() для заполнения этого поля. Например, если вы обрабатываете сообщение установления соединения от функции open() , причем ваш администратор ресурса предоставляет доступ «только для чтения», а клиент хотел открыть ресурс на запись, вы возвратите клиенту через errno код EROFS при помощи (обычно) _RESMGR_STATUS(ctp, EROFS) . |
offset |
Текущее смещение (в байтах) в клиентском буфере сообщений. Имеет смысл для базового уровня библиотеки только при чтении составных сообщений функцией resmgr_msgreadv() . |
size |
Этот параметр говорит, сколько байт в буфере сообщения, переданном вашей функции-обработчику, являются достоверными. Это важная цифра, поскольку она указывает на то, требуется ли читать дополнительные данные от клиента (например, если не все данные были считаны базовым уровнем библиотеки), и надо ли выделить память для ответа клиенту (например, для ответа на запрос read() ). (Отметим, что в версии 2.00 есть ошибка, из-за которой это поле не заполняется в случае несоставного сообщения установления соединения. Все остальные сообщения обрабатываются корректно. Обходной путь здесь (и только здесь!) заключается в использовании параметра msglen структуры info .) |
iov |
Таблица векторов ввода/вывода, в которую вы можете записывать возвращаемые значения, если это необходимо. Например, когда клиент вызывает read() , и у вас вызывается соответствующий обработчик read() , вам может потребоваться возвратить клиенту данные. Можно задать эти данные при помощи массива iov и возвратить что-нибудь типа _RESMGR_NPARTS(2) , указав тем самым (в нашем случае), векторы iov[0] и iov[1] содержат данные для клиента. Заметьте, что массив iov определен как одноэлементный. Однако, заметьте также, что он очень удобно расположен в конце структуры. Фактическое число элементов в массиве iov определяете вы сами, когда присваиваете значение полю nparts_max вышеупомянутой управляющей структуры (см. параграф «Управляющая структура resmgr_attr_t »). |
Структура администратора ресурсов
Читать дальше