RTT自动初始化

1. 自动初始化API

/* board init routines will be called in board_init() function */
#define INIT_BOARD_EXPORT(fn)           INIT_EXPORT(fn, "1")

/* components pre-initialization (pure software initilization) */
#define INIT_PREV_EXPORT(fn)            INIT_EXPORT(fn, "2")
/* device initialization */
#define INIT_DEVICE_EXPORT(fn)          INIT_EXPORT(fn, "3")
/* components initialization (dfs, lwip, ...) */
#define INIT_COMPONENT_EXPORT(fn)       INIT_EXPORT(fn, "4")
/* environment initialization (mount disk, ...) */
#define INIT_ENV_EXPORT(fn)             INIT_EXPORT(fn, "5")
/* appliation initialization (rtgui application etc ...) */
#define INIT_APP_EXPORT(fn)             INIT_EXPORT(fn, "6")
初始化顺序API描述
1INIT_BOARD_EXPORT(fn)非常早期的初始化,此时调度器还未启动
2INIT_PREV_EXPORT(fn)主要是用于纯软件的初始化、没有太多依赖的函数
3INIT_DEVICE_EXPORT(fn)外设驱动初始化相关,比如网卡设备
4INIT_COMPONENT_EXPORT(fn)组件初始化,比如文件系统或者 LWIP
5INIT_ENV_EXPORT(fn)系统环境初始化,比如挂载文件系统
6INIT_APP_EXPORT(fn)应用初始化,比如 GUI 应用

2. 原理分析

2.1 INIT_EXPORT函数

各个初始化函数可以看出最终调用的都是INIT_EXPORT函数,只是传参不同

#define INIT_EXPORT(fn, level)                                                       \
    RT_USED const init_fn_t __rt_init_##fn SECTION(".rti_fn." level) = fn
/*
	1. fn表示需要初始化的函数,传参为函数指针
	2. level表示将函数指针放到哪一个段
*/

2.2 预备知识

  1. RT_USED

    #define RT_USED                     __attribute__((used))
    /* 标记为attribute__((used))的函数被标记在目标文件中,以避免链接器删除未使用的节。*/
    
  2. init_fn_t 类型

    typedef int (*init_fn_t)(void);
    /* 定义了一个返回值为int,函数参数为void的一个函数指针类型并重命名为init_fn_t。 */
    
  3. SECTION

    #define SECTION(x)                  __attribute__((section(x)))
    /* 将作用的函数或数据放入指定名为name的输入段中 */
    
  4. 将宏展开

    RT_USED const init_fn_t __rt_init_fn SECTION(".rti_fn." level) = fn
    

    函数 fn 的指针赋值给__rt_init_fn这个变量,这个变量的类型是RT_USED const init_fn_t,这个变量存放在指定的段.rti_fn.level中。所以函数使用自动初始化宏导出后,这些数据段中就会存储指向各个初始化函数的指针。当我们对这些指针进行解引用的时候也就相当于执行了相应的函数。

2.3 段的划分

在 component.c中对各个段进行了划分,源码如下

static int rti_start(void)
{
    return 0;
}
INIT_EXPORT(rti_start, "0");

static int rti_board_start(void)
{
    return 0;
}
INIT_EXPORT(rti_board_start, "0.end");

static int rti_board_end(void)
{
    return 0;
}
INIT_EXPORT(rti_board_end, "1.end");

static int rti_end(void)
{
    return 0;
}
INIT_EXPORT(rti_end, "6.end");

上面使用 INIT_EXPORT 宏导出的段分布如下表所示

序号段名函数指针/函数名
1.rti_fn.0__rt_init_rti_start
2.rti_fn.0.end__rti_init_rti_board_start
3.rti_fn.1.end__rti_init_rti_board_end
4.rti_fn.6.end__rti_init_rti_end

__rti_init_rti_end

序号段名函数指针/函数名
1.rti_fn.0__rt_init_rti_start
2.rti_fn.0.end__rti_init_rti_board_start
.rti_fn.1INIT_BOARD_EXPORT(fn)
4.rti_fn.1.end__rti_init_rti_board_end
5.rti_fn.2INIT_PREV_EXPORT(fn)
6.rti_fn.3INIT_DEVICE_EXPORT(fn)
7.rti_fn.4INIT_COMPONENT_EXPORT(fn)
8.rti_fn.5INIT_ENV_EXPORT(fn)
9.rti_fn.6INIT_APP_EXPORT(fn)
10.rti_fn.6.end__rti_init_rti_end

2.4 rt_components_board_init 函数

void rt_components_board_init(void)
{
	/* …………………………………… */
    volatile const init_fn_t *fn_ptr;s
    for (fn_ptr = &__rt_init_rti_board_start; fn_ptr < &__rt_init_rti_board_end; fn_ptr++)
    {
        (*fn_ptr)();
    }
}

这段代码定义了一个 fn_ptr 指针,当指针的范围在 __rt_init_rti_board_start 和 __rt_init_rti_board_end 范围之内时就对该指针进行解引用,这里的指针就是自动初始化时放的函数指针,所以这里就相当与函数的执行。也就是执行了 INIT_BOARD_EXPORT(fn) 导出的函数

2.5 rt_components_init 函数

void rt_components_board_init(void)
{
	/* …………………………………… */
	volatile const init_fn_t *fn_ptr;
    for (fn_ptr = &__rt_init_rti_board_end; fn_ptr < &__rt_init_rti_end; fn_ptr++)
    {
        (*fn_ptr)();
    }
}

定义了一个 fn_ptr 指针,当指针的范围在 __rt_init_rti_board_end __rt_init_rti_end范围之内时就对该指针进行解引用,这里的指针就是自动初始化时放的函数指针,所以这里就相当与函数的执行。也就是执行了INIT_PREV_EXPORT(fn)INIT_APP_EXPORT(fn) 这两个段之间导出的函数

  • rt_components_board_init()完成了第 1 段,也就是初始化了由INIT_BOARD_EXPORT(fn)的初始化的所有函数,也就是__rt_init_rti_board_start到 __rt_init_rti_board_end之间的函数指针。
  • rt_components_init()完成了第2 到第6 段,也就是按顺序初始化了由INIT_PREV_EXPORT(fn)到INIT_DEVICE_EXPORT(fn)到INIT_COMPONENT_EXPORT(fn)、INIT_ENV_EXPORT(fn)、INIT_APP_EXPORT(fn)初始化的所有函数,也就是从__rt_init_rti_board_end到__rt_init_rti_end之间的函数指针。
  • 当使用自动初始化导出宏去初始化一个函数时,是由系统中的这两个函数进行遍历函数指针执行的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值