Расширение OCB

Расширение OCB

В ряде случаев у вас может возникнуть необходимость расширения OCB. Процедура эта является относительно безболезненной. Обычно OCB расширяют дополнительными флагами, характеризующими каждый конкретный open(). Один такой флаг можно было бы использовать с обработчиком io_unblock() для кэширования значения флага ядра _NTO_MI_UNBLOCK_REQ (подробнее см. параграф «Применение флага _NTO_MI_UNBLOCK_REQ» в главе «Обмен сообщениями»).

Для расширения блока OCB вам нужно будет обеспечить две дополнительных функции: одну для выделения OCB, и одну — для его освобождения. Затем вы должны будете привязать эти две функции к записи точки монтирования. (Да-да, совершенно верно — вам понадобится запись точки монтирования, даже если только для этого.) И наконец, вы должны будете определить ваш собственный тип OCB, чтобы все прототипы в программе были корректны.

Давайте рассмотрим сначала описание типа OCB, а затем уже поглядим, как переопределяются функции:

#define IOFUNC_OCB_T struct my_ocb

#include <sys/iofunc.h>

Это сообщает включаемому файлу <sys/iofunc.h>, что именованная константа IOFUNC_OCB_T теперь указывает на вашу новую усовершенствованную структуру OCB.

Очень важно иметь в виду, что ваш «расширенный» OCB должен содержать «стандартный» OCB в качестве своего первого элемента! Это так, потому что вспомогательная библиотека POSIX везде передает указатель на то, что она считает стандартным OCB — о вашем расширенном OCB ей ничего не известно, так что первый элемент данных, расположенный по этому указателю, должен соответствовать стандартному OCB.

Вот наш расширенный OCB:

typedef struct my_ocb {

 iofunc_ocb_t normal_ocb;

 int          my_extra_flags;

 ...

} my_ocb_t;

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

// Декларации

iofunc_mount_t mount;

iofunc_funcs_t mount_funcs;

// Задать в записи точки монтирования

// наши функции выделения/освобождения

// _IOFUNC_NFUNCS взята из .h-файла

mount_funcs.nfuncs = _IOFUNC_NFUNCS;

// Новая функция выделения OCB

mount_funcs.ocb_calloc = my_ocb_calloc;

// Новая функция освобождения OCB

mount_funcs.ocb_free = my_ocb_free;

// Настроить запись точки монтирования

memset(&mount, 0, sizeof(mount));

После этого остается только привязать запись точки монтирования к атрибутной записи:

...

attr.mount = &mount;

Функции my_ocb_calloc() и my_ocb_free() отвечают за выделение обнуленного расширенного OCB и освобождения OCB, соответственно. Вот их прототипы:

IOFUNC_OCB_T* my_ocb_calloc(resmgr_context_t *ctp,

 IOFUNC_ATTR_T *attr);

void my_ocb_free(IOFUNC_OCB_T *ocb);

Это означает, что функции my_ocb_calloc() передаются одновременно и внутренний контекст администратора ресурсов, и атрибутная запись. Функция отвечает за возврат обнуленного OCB. Функция my_ocb_free() получает OCB и отвечает за освобождение выделенной под него памяти.

Для этих двух функций имеются два интересных применения (которые ничем не связаны с выполнением расширения блока OCB):

• контроль распределения/освобождения блока OCB;

• обеспечение более эффективного распределения/ освобождения

Контроль за OCB

В этом случае вы можете просто «подключиться» к функциям распределения/освобождения и контролировать использование OCB (например, вам может быть необходимо ограничить суммарное количество OCB). Это может оказаться полезным, если вы не перехватываете функцию io_open(), но создание (и, возможно, удаление) OCB все-таки хотите контролировать.

Более эффективное распределение

Другое применение для переопределения встроенных библиотечных функций распределения/освобождения OCB может заключаться в том, что вы можете захотеть хранить OCB в свободном списке вместо использования библиотечных calloc() и free(). Если вы распределяете и освобождаете OCB с большой частотой, это может оказаться более эффективно.