object->cache<->class
第 3 章 内核对象
目录
内核对象,或 Kobj 为内核提供了一个面向对象的 C 编程系统。因此,正在操作的数据包含了如何操作它的描述。这允许在运行时添加和删除接口的操作,并且不会破坏二进制兼容性。
3.2 Kobj 操作
Kobj 通过生成方法描述来工作。每个描述都包含一个唯一的 ID 以及一个默认函数。描述的地址用于在类的“方法表”中唯一标识方法。
类是通过创建方法表来构建的,该方法表将一个或多个函数与方法描述相关联。在使用之前,类会被编译。编译会分配一个缓存并将其与类关联。如果另一个引用类的编译尚未为方法描述分配唯一 ID,则会为方法表中的每个方法描述分配一个唯一 ID。对于要使用的每个方法,都会通过脚本生成一个函数,以限定参数并自动引用方法描述以进行查找。生成的函数通过使用与方法描述关联的唯一 ID 作为哈希值来查找方法,该哈希值位于与对象类关联的缓存中。如果方法未被缓存,则生成的函数将继续使用类的表来查找方法。如果找到该方法,则使用类中的关联函数;否则,将使用与方法描述关联的默认函数。
这些间接引用可以可视化为如下所示
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.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()
。要创建方法表,请创建一个以 NULL 条目结尾的 kobj_method_t 数组。每个非 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 部分上使用 kobj_init()
;否则,您可以使用 kobj_create()
自动分配和初始化对象的 Kobj 部分。kobj_init()
也可以用来更改对象使用的类。
要将 Kobj 集成到对象中,应使用宏 KOBJ_FIELDS。
例如
struct foo_data { KOBJ_FIELDS; foo_foo; foo_bar; };
上次修改时间:2024年3月9日 由 Danilo G. Baio 修改