由于DragonOS的驱动、模块变多了,如果每个模块的初始化都手动加个函数调用的话,对条件编译非常不友好。因此我使用Rust的procmacro开发了一个库,叫做unified-init,用于统一初始化内核的模块。
设计了“初始化器”和”初始化器数组“两个对象。通过在函数上方加lint,编译期自动生成初始化器,并使用linkme库,在链接时,把初始化器链接到指定的初始化器数组内。然后我们就能在某个地方统一的调用数组内所有的初始化器了。
下面给了一个示例:
use system_error::SystemError;
use unified_init::define_unified_initializer_slice;
use unified_init_macros::unified_init;
/// 初始化函数都将会被放到这个列表中
define_unified_initializer_slice!(INITIALIZER_LIST);
#[unified_init(INITIALIZER_LIST)]
fn init1() -> Result<(), SystemError> {
Ok(())
}
#[unified_init(INITIALIZER_LIST)]
fn init2() -> Result<(), SystemError> {
Ok(())
}
fn main() {
assert_eq!(INITIALIZER_LIST.len(), 2);
}
本文的源码解析基于
https://github.com/DragonOS-Community/DragonOS/commit/91e9d4ab55ef960f57a1b6287bc523ca4341f67a 这个版本的代码。
代码在kernel/crates/unified-init下。
macros目录是过程宏的代码,也是这个库的核心,因此本文只对macros目录下的lib.rs进行讲解。
unified_init
是 DragonOS 中的一个过程宏,它主要用于初始化操作,可以用于将一些函数注册到统一初始化列表中。它的主要工作流程是:
INITIALIZER_LIST
和一个指向目标链表的路径 initializer_instance
。Result<(), SystemError>
,且没有参数。UnifiedInitializer
:如果函数签名满足要求,那么它会生成一个全局变量 unified_initializer
,并将其注册到目标链表中。这个全局变量是 unified_init::UnifiedInitializer
的实例,用于在程序运行时初始化指定的函数。 具体来说,generate_unified_initializer
函数会生成一个类似这样的代码片段:static unified_initializer_xxx_xxx: unified_init::UnifiedInitializer = ::unified_init::UnifiedInitializer::new("xxx", &(xxx as ::unified_init::UnifiedInitFunction));
这里的 "xxx" 是函数的全名,"xxx" 是 unified_init::UnifiedInitFunction
的别名。
整个过程宏的主要目的是为了简化初始化操作,使得多个函数的初始化操作可以统一进行,避免重复的代码。