rt_thread有一个开机不用显示调用函数,可以自动进行初始化函数调用的功能。前提是需要在定义函数处通过INIT_BOARD_EXPORT(fn)、 INIT_PREV_EXPORT(fn)、INIT_DEVICE_EXPORT(fn) 、INIT_COMPONENT_EXPORT(fn)、 INIT_ENV_EXPORT(fn)、INIT_APP_EXPORT(fn) 等宏定义进行声明;
比如我们定义一个函数:
void my_test_fun(void)
{
printf("HelloWorld");
}
通过添加如下声明后:
INIT_BOARD_EXPORT(my_test_fun);
my_test_fun函数将在系统启动阶段自动完成调用。
我们先说该机制的实现原理:
原理就是在进行INIT_BOARD_EXPORT(my_test_fun);这种声明时其实是定义了一个函数指针变量,并将该变量放到某个特定的section区域,在启动阶段从该section的起始地址到结束地址进行遍历,将遍历到的函数都进行一次调用,从而达到自动化初始化函数的目的。
涉及到的源码:
/* 定义该宏开启自动初始化机制,未定义则关闭 */
#define RT_USING_COMPONENTS_INIT
/* 定义该宏开启自动初始化机制,未定义则关闭 */
#define RT_USING_COMPONENTS_INIT
/* initialization export */
#ifdef RT_USING_COMPONENTS_INIT //注释:/* 定义该宏开启自动初始化机制,未定义则关闭 */
typedef int (*init_fn_t)(void);
#ifdef _MSC_VER /* we do not support MS VC++ compiler */
#define INIT_EXPORT(fn, level)
#else
#if RT_DEBUG_INIT
struct rt_init_desc
{
const char* fn_name;
const init_fn_t fn;
};
#define INIT_EXPORT(fn, level) \
const char __rti_##fn##_name[] = #fn; \ //定义一个静态字符数组,初始值为函数名对应的字符串字面量。数组名字为由__rti_、fn的字符串字面量,_name拼接而成,这里使用了宏中的 ## 运算符来连接字符串。#fn中#是一个预处理器操作符,它把宏参数 fn 转换成一个字符串字面量。
RT_USED const struct rt_init_desc __rt_init_desc_##fn SECTION(".rti_fn." level) = \ //定义一个struct rt_init_desc类型的静态变量,变量名通过宏##运算符拼接__rt_init_desc_和fn名而成,变量初始化值有两个值,第一个值是由__rti_和fn名称和_name拼接的字符串,第二个值是fn函数指针。RT_USED 用来告诉链接器不要优化掉该变量。SECTION(".rti_fn." level)告诉链接器将这个变量放置到一个特定的段(section)中。段名由 .rti_fn. 加上 level 的值组成。
{ __rti_##fn##_name, fn};
#else
#define INIT_EXPORT(fn, level) \
RT_USED const init_fn_t __rt_init_##fn SECTION(".rti_fn." level) = fn //定义一个函数指针变量变量,初始值为fn,变量名由__rt_init_和fn名称拼接而成。RT_USED 用来告诉链接器不要优化掉该变量。SECTION(".rti_fn." level)告诉链接器将这个变量放置到一个特定的段(section)中。段名由 .rti_fn. 加上 level 的值组成。
#endif
#endif
#else
#define INIT_EXPORT(fn, level)
#endif
/* board init routines will be called in board_init() function */
#define INIT_BOARD_EXPORT(fn) INIT_EXPORT(fn, "1")
/* pre/device/component/env/app init routines will be called in init_thread */
/* 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")
#if !defined(RT_USING_FINSH)
/* define these to empty, even if not include finsh.h file */
#define FINSH_FUNCTION_EXPORT(name, desc)
#define FINSH_FUNCTION_EXPORT_ALIAS(name, alias, desc)
#define FINSH_VAR_EXPORT(name, type, desc)
#define MSH_CMD_EXPORT(command, desc)
#define MSH_CMD_EXPORT_ALIAS(command, alias, desc)
#elif !defined(FINSH_USING_SYMTAB)
#define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc)
#endif
#ifdef RT_USING_COMPONENTS_INIT
/*
* Components Initialization will initialize some driver and components as following
* order:
* rti_start --> 0
* BOARD_EXPORT --> 1
* rti_board_end --> 1.end
*
* DEVICE_EXPORT --> 2
* COMPONENT_EXPORT --> 3
* FS_EXPORT --> 4
* ENV_EXPORT --> 5
* APP_EXPORT --> 6
*
* rti_end --> 6.end
*
* These automatically initialization, the driver or component initial function must
* be defined with:
* INIT_BOARD_EXPORT(fn);
* INIT_DEVICE_EXPORT(fn);
* ...
* INIT_APP_EXPORT(fn);
* etc.
*/
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");
/**
* RT-Thread Components Initialization for board
*/
void rt_components_board_init(void)
{
#if RT_DEBUG_INIT
int result;
const struct rt_init_desc *desc;
for (desc = &__rt_init_desc_rti_board_start; desc < &__rt_init_desc_rti_board_end; desc ++)
{
rt_kprintf("initialize %s", desc->fn_name);
result = desc->fn();
rt_kprintf(":%d done\n", result);
}
#else
const init_fn_t *fn_ptr;
for (fn_ptr = &__rt_init_rti_board_start; fn_ptr < &__rt_init_rti_board_end; fn_ptr++)
{
(*fn_ptr)();
}
#endif
}
/**
* RT-Thread Components Initialization
*/
void rt_components_init(void)
{
#if RT_DEBUG_INIT
int result;
const struct rt_init_desc *desc;
rt_kprintf("do components initialization.\n");
for (desc = &__rt_init_desc_rti_board_end; desc < &__rt_init_desc_rti_end; desc ++)
{
rt_kprintf("initialize %s", desc->fn_name);
result = desc->fn();
rt_kprintf(":%d done\n", result);
}
#else
const init_fn_t *fn_ptr;
for (fn_ptr = &__rt_init_rti_board_end; fn_ptr < &__rt_init_rti_end; fn_ptr ++)
{
(*fn_ptr)();
}
#endif
}
#endif /* RT_USING_COMPONENTS_INIT */
从map中看到: