object->cache<->class
Глава 3. Объекты ядра
Этот перевод может быть устаревшим. Для того, чтобы помочь с переводом, пожалуйста, обратитесь к Сервер переводов FreeBSD.
Содержание
Объекты ядра, или Kobj, предоставляют объектно-ориентированную систему программирования на языке C для ядра. Таким образом, данные, с которыми производится работа, содержат описание того, как над ними следует выполнять операции. Это позволяет добавлять и удалять операции из интерфейса во время выполнения без нарушения бинарной совместимости.
3.1. Терминология
- Объект
Набор данных - структура данных - аллокация данных.
- Метод
Операция — функция.
- Класс
Один или несколько методов.
- Интерфейс
Стандартный набор из одного или нескольких методов.
3.2. Как работает Kobj
Kobj работает путем генерации описаний методов. Каждое описание содержит уникальный идентификатор, а также функцию по умолчанию. Адрес описания используется для однозначной идентификации метода в таблице методов класса.
Класс создается путем построения таблицы методов, связывающей одну или несколько функций с описаниями методов. Перед использованием класс компилируется. В процессе компиляции выделяется кэш и связывается с классом. Уникальный идентификатор назначается каждому описанию метода в таблице методов класса, если это еще не было сделано другой ссылающейся компиляцией класса. Для каждого используемого метода скриптом генерируется функция для проверки аргументов и автоматического обращения к описанию метода для поиска. Сгенерированная функция ищет метод, используя уникальный идентификатор, связанный с описанием метода, в качестве хэша для доступа к кэшу, связанному с классом объекта. Если метод не найден в кэше, сгенерированная функция использует таблицу класса для поиска метода. Если метод найден, используется связанная с ним функция внутри класса; в противном случае используется функция по умолчанию, связанная с описанием метода.
Эти перенаправления можно визуализировать следующим образом:
3.3. Использование Kobj
3.3.2. Функции
void kobj_class_compile(kobj_class_t cls); void kobj_class_compile_static(kobj_class_t cls, kobj_ops_t ops); void kobj_class_free(kobj_class_t cls); kobj_t kobj_create(kobj_class_t cls, struct malloc_type *mtype, int mflags); void kobj_init(kobj_t obj, kobj_class_t cls); void kobj_delete(kobj_t obj, struct malloc_type *mtype);
3.3.3. Макросы
KOBJ_CLASS_FIELDS KOBJ_FIELDS DEFINE_CLASS(name, methods, size) KOBJMETHOD(NAME, FUNC)
3.3.5. Создание шаблона интерфейса
Первым шагом в использовании Kobj является создание интерфейса. Создание интерфейса включает в себя создание шаблона, который скрипт src/sys/kern/makeobjops.pl может использовать для генерации заголовочного файла и кода объявлений методов и функций поиска методов.
В этом шаблоне используются следующие ключевые слова: #include
, INTERFACE
, CODE
, EPILOG
, HEADER
, METHOD
, PROLOG
, STATICMETHOD
и DEFAULT
.
Включение директивы #include
и всего, что следует за ней, копируется дословно в начало сгенерированного файла с кодом.
Например:
#include <sys/foo.h>
Ключевое слово INTERFACE
используется для определения имени интерфейса. Это имя объединяется с каждым именем метода в формате [имя интерфейса]_[имя метода]. Его синтаксис: INTERFACE [имя интерфейса];
.
Например:
INTERFACE foo;
Ключевое слово CODE
копирует свои аргументы дословно в файл кода. Его синтаксис: CODE { [что угодно] };
Например:
CODE { struct foo * foo_alloc_null(struct bar *) { return NULL; } };
Ключевое слово HEADER
копирует свои аргументы в заголовочный файл без изменений. Его синтаксис: HEADER { [что угодно] };
Например:
HEADER { struct mumble; struct grumble; };
Ключевое слово METHOD
описывает метод. Его синтаксис: METHOD [возвращаемый тип] [имя метода] { [объект [, аргументы]] };
Например:
METHOD int bar { struct object *; struct foo *; struct bar; };
Ключевое слово DEFAULT
может следовать за ключевым словом METHOD
. Оно расширяет ключевое слово METHOD
, включая функцию по умолчанию для метода. Расширенный синтаксис выглядит так: METHOD [тип возвращаемого значения] [имя метода] { [объект; [другие аргументы]] } DEFAULT [функция по умолчанию];
Например:
METHOD int bar { struct object *; struct foo *; int bar; } DEFAULT foo_hack;
Ключевое слово STATICMETHOD
используется аналогично ключевому слову METHOD
, за исключением того, что данные kobj не находятся в начале структуры объекта, поэтому приведение к типу kobj_t было бы некорректным. Вместо этого STATICMETHOD
полагается на то, что данные Kobj указаны как 'ops'. Это также полезно для вызова методов напрямую из таблицы методов класса.
Ключевые слова PROLOG
и EPILOG
вставляют код непосредственно перед или сразу после METHOD
, к которому они прикреплены. Эта функция в основном используется для профилирования в ситуациях, когда сложно получить информацию другим способом.
Другие полные примеры:
src/sys/kern/bus_if.m src/sys/kern/device_if.m
3.3.6. Создание класса
Второй шаг в использовании Kobj — это создание класса. Класс состоит из имени, таблицы методов и размера объектов, если используются средства обработки объектов Kobj. Для создания класса используйте макрос DEFINE_CLASS()
. Чтобы создать таблицу методов, создайте массив элементов kobj_method_t, завершающийся записью NULL. Каждую не-NULL запись можно создать с помощью макроса KOBJMETHOD()
.
Например:
DEFINE_CLASS(fooclass, foomethods, sizeof(struct foodata)); kobj_method_t foomethods[] = { KOBJMETHOD(bar_doo, foo_doo), KOBJMETHOD(bar_foo, foo_foo), { NULL, NULL} };
Класс должен быть "скомпилирован". В зависимости от состояния системы на момент инициализации класса, необходимо использовать статически выделенный кэш, "таблицу операций". Это может быть достигнуто путем объявления struct kobj_ops
и использования kobj_class_compile_static();
в противном случае следует использовать kobj_class_compile()
.
3.3.7. Создание объекта
Третий шаг в использовании Kobj связан с определением объекта. Процедуры создания объекта Kobj предполагают, что данные Kobj находятся в начале объекта. Если это не подходит, вам придется самостоятельно выделить память для объекта, а затем использовать kobj_init()
для части объекта, относящейся к Kobj; в противном случае вы можете использовать kobj_create()
для автоматического выделения и инициализации части объекта, относящейся к Kobj. kobj_init()
также может использоваться для изменения класса, который использует объект.
Для интеграции Kobj в объект следует использовать макрос KOBJ_FIELDS
.
Например
struct foo_data { KOBJ_FIELDS; foo_foo; foo_bar; };
3.3.8. Вызов методов
Последним шагом в использовании Kobj является простое использование сгенерированных функций для вызова нужного метода в классе объекта. Это так же просто, как использование имени интерфейса и имени метода с небольшими изменениями. Имя интерфейса должно быть соединено с именем метода с использованием символа '_' между ними, все в верхнем регистре.
Например, если имя интерфейса было foo, а метод — bar, то вызов будет выглядеть следующим образом:
[return value = ] FOO_BAR(object [, other parameters]);
Изменено: 14 октября 2025 г. by Vladlen Popolitov