Глава 3. Объекты ядра | FreeBSD Documentation Portal
Description: Объекты ядра
Keywords: kernel objects,kobj,guide,FreeBSD

# Глава 3. Объекты ядра

Этот перевод может быть устаревшим. Для того, чтобы помочь с переводом, пожалуйста, обратитесь к Сервер переводов FreeBSD.

Объекты ядра, или Kobj, предоставляют объектно-ориентированную систему программирования на языке C для ядра. Таким образом, данные, с которыми производится работа, содержат описание того, как над ними следует выполнять операции. Это позволяет добавлять и удалять операции из интерфейса во время выполнения без нарушения бинарной совместимости.

## 3.1. Терминология

Объект

  Набор данных - структура данных - аллокация данных.

Метод

  Операция — функция.

Класс

  Один или несколько методов.

Интерфейс

  Стандартный набор из одного или нескольких методов.

## 3.2. Как работает Kobj

Kobj работает путем генерации описаний методов. Каждое описание содержит уникальный идентификатор, а также функцию по умолчанию. Адрес описания используется для однозначной идентификации метода в таблице методов класса.

Класс создаётся путем построения таблицы методов, связывающей одну или несколько функций с описаниями методов. Перед использованием класс компилируется. В процессе компиляции выделяется кэш и связывается с классом. Уникальный идентификатор назначается каждому описанию метода в таблице методов класса, если это ещё не было сделано другой компиляцией, ссылающейся на этот класс. Для каждого используемого метода скриптом генерируется функция для проверки аргументов и автоматического обращения к описанию метода для поиска. Сгенерированная функция ищет метод, используя уникальный идентификатор, связанный с описанием метода, в качестве хэша для доступа к кэшу, связанному с классом объекта. Если метод не найден в кэше, сгенерированная функция использует таблицу класса для поиска метода. Если метод найден, используется связанная с ним функция внутри класса; в противном случае используется функция по умолчанию, связанная с описанием метода.

Эти перенаправления можно визуализировать следующим образом:

    object->cache<->class

## 3.3. Использование Kobj

### 3.3.1. Структуры

    struct kobj_method

### 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.4. Заголовки

    <sys/param.h>
    <sys/kobj.h>

### 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]);

### 3.3.9. Очистка

Когда объект, выделенный через `kobj_create()`, больше не нужен, можно вызвать для него `kobj_delete()`, а когда класс больше не используется, можно вызвать для него `kobj_class_free()`.

Изменено: 17 мая 2026 г. by Vladlen Popolitov

Назад
Главная
Далее