Path: blob/main/documentation/content/ru/books/arch-handbook/kobj/_index.adoc
18098 views
---
description: 'Объекты ядра'
next: books/arch-handbook/jail
params:
path: /books/arch-handbook/kobj/
prev: books/arch-handbook/locking
showBookMenu: 'true'
tags: ["kernel objects", "kobj", "guide", "FreeBSD"]
title: 'Глава 3. Объекты ядра'
weight: 4
---
[[kernel-objects]]
= Объекты ядра
:doctype: book
:toc: macro
:toclevels: 1
:icons: font
:sectnums:
:sectnumlevels: 6
:sectnumoffset: 3
:partnums:
:source-highlighter: rouge
:experimental:
:images-path: books/arch-handbook/
ifdef::env-beastie[]
ifdef::backend-html5[]
:imagesdir: ../../../../images/{images-path}
endif::[]
ifndef::book[]
include::shared/authors.adoc[]
include::shared/mirrors.adoc[]
include::shared/releases.adoc[]
include::shared/attributes/attributes-{{% lang %}}.adoc[]
include::shared/{{% lang %}}/teams.adoc[]
include::shared/{{% lang %}}/mailing-lists.adoc[]
include::shared/{{% lang %}}/urls.adoc[]
toc::[]
endif::[]
ifdef::backend-pdf,backend-epub3[]
include::../../../../../shared/asciidoctor.adoc[]
endif::[]
endif::[]
ifndef::env-beastie[]
toc::[]
include::../../../../../shared/asciidoctor.adoc[]
endif::[]
Объекты ядра, или _Kobj_, предоставляют объектно-ориентированную систему программирования на языке C для ядра. Таким образом, данные, с которыми производится работа, содержат описание того, как над ними следует выполнять операции. Это позволяет добавлять и удалять операции из интерфейса во время выполнения без нарушения бинарной совместимости.
[[kernel-objects-term]]
== Терминология
Объект::
Набор данных - структура данных - аллокация данных.
Метод::
Операция — функция.
Класс::
Один или несколько методов.
Интерфейс::
Стандартный набор из одного или нескольких методов.
[[kernel-objects-operation]]
== Как работает Kobj
Kobj работает путем генерации описаний методов. Каждое описание содержит уникальный идентификатор, а также функцию по умолчанию. Адрес описания используется для однозначной идентификации метода в таблице методов класса.
Класс создаётся путем построения таблицы методов, связывающей одну или несколько функций с описаниями методов. Перед использованием класс компилируется. В процессе компиляции выделяется кэш и связывается с классом. Уникальный идентификатор назначается каждому описанию метода в таблице методов класса, если это ещё не было сделано другой компиляцией, ссылающейся на этот класс. Для каждого используемого метода скриптом генерируется функция для проверки аргументов и автоматического обращения к описанию метода для поиска. Сгенерированная функция ищет метод, используя уникальный идентификатор, связанный с описанием метода, в качестве хэша для доступа к кэшу, связанному с классом объекта. Если метод не найден в кэше, сгенерированная функция использует таблицу класса для поиска метода. Если метод найден, используется связанная с ним функция внутри класса; в противном случае используется функция по умолчанию, связанная с описанием метода.
Эти перенаправления можно визуализировать следующим образом:
[.programlisting]
....
object->cache<->class
....
[[kernel-objects-using]]
== Использование Kobj
=== Структуры
[.programlisting]
....
struct kobj_method
....
=== Функции
[.programlisting]
....
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);
....
=== Макросы
[.programlisting]
....
KOBJ_CLASS_FIELDS
KOBJ_FIELDS
DEFINE_CLASS(name, methods, size)
KOBJMETHOD(NAME, FUNC)
....
=== Заголовки
[.programlisting]
....
<sys/param.h>
<sys/kobj.h>
....
=== Создание шаблона интерфейса
Первым шагом в использовании Kobj является создание интерфейса. Создание интерфейса включает в себя создание шаблона, который скрипт [.filename]#src/sys/kern/makeobjops.pl# может использовать для генерации заголовочного файла и кода объявлений методов и функций поиска методов.
В этом шаблоне используются следующие ключевые слова: `#include`, `INTERFACE`, `CODE`, `EPILOG`, `HEADER`, `METHOD`, `PROLOG`, `STATICMETHOD` и `DEFAULT`.
Включение директивы `#include` и всего, что следует за ней, копируется дословно в начало сгенерированного файла с кодом.
Например:
[.programlisting]
....
#include <sys/foo.h>
....
Ключевое слово `INTERFACE` используется для определения имени интерфейса. Это имя объединяется с каждым именем метода в формате [имя интерфейса]_[имя метода]. Его синтаксис: `INTERFACE [имя интерфейса];`.
Например:
[.programlisting]
....
INTERFACE foo;
....
Ключевое слово `CODE` копирует свои аргументы дословно в файл кода. Его синтаксис: `CODE { [что угодно] };`
Например:
[.programlisting]
....
CODE {
struct foo * foo_alloc_null(struct bar *)
{
return NULL;
}
};
....
Ключевое слово `HEADER` копирует свои аргументы в заголовочный файл без изменений. Его синтаксис: `HEADER { [что угодно] };`
Например:
[.programlisting]
....
HEADER {
struct mumble;
struct grumble;
};
....
Ключевое слово `METHOD` описывает метод. Его синтаксис: `METHOD [возвращаемый тип] [имя метода] { [объект [, аргументы]] };`
Например:
[.programlisting]
....
METHOD int bar {
struct object *;
struct foo *;
struct bar;
};
....
Ключевое слово `DEFAULT` может следовать за ключевым словом `METHOD`. Оно расширяет ключевое слово `METHOD`, включая функцию по умолчанию для метода. Расширенный синтаксис выглядит так: `METHOD [тип возвращаемого значения] [имя метода] { [объект; [другие аргументы]] } DEFAULT [функция по умолчанию];`
Например:
[.programlisting]
....
METHOD int bar {
struct object *;
struct foo *;
int bar;
} DEFAULT foo_hack;
....
Ключевое слово `STATICMETHOD` используется аналогично ключевому слову `METHOD`, за исключением того, что данные kobj не находятся в начале структуры объекта, поэтому приведение к типу kobj_t было бы некорректным. Вместо этого `STATICMETHOD` полагается на то, что данные Kobj указаны как 'ops'. Это также полезно для вызова методов напрямую из таблицы методов класса.
Ключевые слова `PROLOG` и `EPILOG` вставляют код непосредственно перед или сразу после `METHOD`, к которому они прикреплены. Эта функция в основном используется для профилирования в ситуациях, когда сложно получить информацию другим способом.
Другие полные примеры:
[.programlisting]
....
src/sys/kern/bus_if.m
src/sys/kern/device_if.m
....
=== Создание класса
Второй шаг в использовании Kobj — это создание класса. Класс состоит из имени, таблицы методов и размера объектов, если используются средства обработки объектов Kobj. Для создания класса используйте макрос `DEFINE_CLASS()`. Чтобы создать таблицу методов, создайте массив элементов kobj_method_t, завершающийся записью NULL. Каждую не-NULL запись можно создать с помощью макроса `KOBJMETHOD()`.
Например:
[.programlisting]
....
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()`.
=== Создание объекта
Третий шаг в использовании Kobj связан с определением объекта. Процедуры создания объекта Kobj предполагают, что данные Kobj находятся в начале объекта. Если это не подходит, вам придется самостоятельно выделить память для объекта, а затем использовать `kobj_init()` для части объекта, относящейся к Kobj; в противном случае вы можете использовать `kobj_create()` для автоматического выделения и инициализации части объекта, относящейся к Kobj. `kobj_init()` также может использоваться для изменения класса, который использует объект.
Для интеграции Kobj в объект следует использовать макрос `KOBJ_FIELDS`.
Например
[.programlisting]
....
struct foo_data {
KOBJ_FIELDS;
foo_foo;
foo_bar;
};
....
=== Вызов методов
Последним шагом в использовании Kobj является простое использование сгенерированных функций для вызова нужного метода в классе объекта. Это так же просто, как использование имени интерфейса и имени метода с небольшими изменениями. Имя интерфейса должно быть соединено с именем метода с использованием символа '_' между ними, все в верхнем регистре.
Например, если имя интерфейса было foo, а метод — bar, то вызов будет выглядеть следующим образом:
[.programlisting]
....
[return value = ] FOO_BAR(object [, other parameters]);
....
=== Очистка
Когда объект, выделенный через `kobj_create()`, больше не нужен, можно вызвать для него `kobj_delete()`, а когда класс больше не используется, можно вызвать для него `kobj_class_free()`.