Unified-init:为DragonOS开发的模块统一初始化组件

2023-12-28 09:57:28 浏览数 (1)

前言

由于DragonOS的驱动、模块变多了,如果每个模块的初始化都手动加个函数调用的话,对条件编译非常不友好。因此我使用Rust的procmacro开发了一个库,叫做unified-init,用于统一初始化内核的模块。

原理

设计了“初始化器”和”初始化器数组“两个对象。通过在函数上方加lint,编译期自动生成初始化器,并使用linkme库,在链接时,把初始化器链接到指定的初始化器数组内。然后我们就能在某个地方统一的调用数组内所有的初始化器了。

使用

下面给了一个示例:

代码语言:javascript复制
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 中的一个过程宏,它主要用于初始化操作,可以用于将一些函数注册到统一初始化列表中。它的主要工作流程是:

  • 解析属性参数:unified_init 首先会解析传入的属性参数,这包括初始化列表名 INITIALIZER_LIST 和一个指向目标链表的路径 initializer_instance
  • 获取当前函数:然后,它会从输入的宏中解析出一个函数定义。这个函数需要满足特定的签名要求,即返回类型为 Result<(), SystemError>,且没有参数。
  • 检查函数签名:接下来,它会检查解析出的函数的签名是否满足要求。如果不满足,就会返回一个错误。
  • 生成 UnifiedInitializer:如果函数签名满足要求,那么它会生成一个全局变量 unified_initializer,并将其注册到目标链表中。这个全局变量是 unified_init::UnifiedInitializer 的实例,用于在程序运行时初始化指定的函数。 具体来说,generate_unified_initializer 函数会生成一个类似这样的代码片段:
代码语言:javascript复制
static unified_initializer_xxx_xxx: unified_init::UnifiedInitializer = ::unified_init::UnifiedInitializer::new("xxx", &(xxx as ::unified_init::UnifiedInitFunction));

这里的 "xxx" 是函数的全名,"xxx" 是 unified_init::UnifiedInitFunction 的别名。

整个过程宏的主要目的是为了简化初始化操作,使得多个函数的初始化操作可以统一进行,避免重复的代码。

0 人点赞