本文共 6117 字,大约阅读时间需要 20 分钟。
RT-Thread 的自动初始化机制使用了自定义 RTI 符号段,将需要在启动时进行初始化的函数指针放到了该段中,形成一张初始化函数表,在系统启动过程中会遍历该表,并调用表中的函数,达到自动初始化的目的。
进入任意一个宏定义,可以查看源码中的宏定义如下:/* 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")
继续展开INIT_EXPORT(fn, level) 如下:
#define INIT_EXPORT(fn, level) \ RT_USED const init_fn_t __rt_init_##fn SECTION(".rti_fn." level) = fn
其中##代表连接符,把__rt_init_与fn这个形参名字链接起来,即__rt_init_fn
查看init_fn_t的定义如下:typedef int (*init_fn_t)(void);
表示用typedef 定义了一个函数指针类型,init_fn_t _rt_init##fn SECTION(".rti_fn." level) = fn表示定义了一个函数指针变量,并初始化,把fn这个函数的地址赋给__rt_init_fn这个函数指针。
其中SECTION(".rti_fn." level)展开如下:#define SECTION(x) __attribute__((section(x)))
_attribute_((section(“name”))) :将作用的函数或数据放入指定名为"name"的输入段中。(在不同的编译器中实现的方式也有所不同。)
总结:作用就是将函数 fn 的地址赋给一个 __rt_init_fn 的指针,然后放入相应 level 的数据段中。所以函数使用自动初始化宏导出后,这些数据段中就会存储指向各个初始化函数的指针。在程序启动后,会分别运行 rt_components_board_init() 与 rt_components_init() 函数,其中 rt_components_board_init()完成了第1段的初始化,rt_components_init()完成了2到6段的初始化。
1、第一个函数 rt_components_board_init() 的实现:void rt_components_board_init(void){ 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)(); }}
2、第二个函数 rt_components_board_init() 的实现:
void rt_components_init(void){ const init_fn_t *fn_ptr; for (fn_ptr = &__rt_init_rti_board_end; fn_ptr < &__rt_init_rti_end; fn_ptr ++) { (*fn_ptr)(); }}
其中__rt_init_rti_board_start,__rt_init_rti_board_end,__rt_init_rti_end表示不同的区间段。
在系统中,定义了这几个空函数:rti_start、rti_board_start、rti_board_end、rti_end。划分成不同的段:0、 0.end 、 1.end 、6.end。 自定义的初始化函数就夹裹在这些段内。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");
这几个函数的导出,加上上面 6 个初始化宏的导出,就有了这样一个表格:
查看map文件可知: 其中__rt_init_finsh_system_init 为内核shell的初始化:int finsh_system_init(void){ rt_err_t result = RT_EOK; rt_thread_t tid;#ifdef FINSH_USING_SYMTAB#if defined(__CC_ARM) || defined(__CLANG_ARM) /* ARM C Compiler */ extern const int FSymTab$$Base; extern const int FSymTab$$Limit; extern const int VSymTab$$Base; extern const int VSymTab$$Limit; finsh_system_function_init(&FSymTab$$Base, &FSymTab$$Limit);#ifndef FINSH_USING_MSH_ONLY finsh_system_var_init(&VSymTab$$Base, &VSymTab$$Limit);#endif#elif defined (__ICCARM__) || defined(__ICCRX__) /* for IAR Compiler */ finsh_system_function_init(__section_begin("FSymTab"), __section_end("FSymTab")); finsh_system_var_init(__section_begin("VSymTab"), __section_end("VSymTab"));#elif defined (__GNUC__) || defined(__TI_COMPILER_VERSION__) /* GNU GCC Compiler and TI CCS */ extern const int __fsymtab_start; extern const int __fsymtab_end; extern const int __vsymtab_start; extern const int __vsymtab_end; finsh_system_function_init(&__fsymtab_start, &__fsymtab_end); finsh_system_var_init(&__vsymtab_start, &__vsymtab_end);#elif defined(__ADSPBLACKFIN__) /* for VisualDSP++ Compiler */ finsh_system_function_init(&__fsymtab_start, &__fsymtab_end); finsh_system_var_init(&__vsymtab_start, &__vsymtab_end);#elif defined(_MSC_VER) unsigned int *ptr_begin, *ptr_end; if(shell) { rt_kprintf("finsh shell already init.\n"); return RT_EOK; } ptr_begin = (unsigned int *)&__fsym_begin; ptr_begin += (sizeof(struct finsh_syscall) / sizeof(unsigned int)); while (*ptr_begin == 0) ptr_begin ++; ptr_end = (unsigned int *) &__fsym_end; ptr_end --; while (*ptr_end == 0) ptr_end --; finsh_system_function_init(ptr_begin, ptr_end);#endif#endif#ifdef RT_USING_HEAP /* create or set shell structure */ shell = (struct finsh_shell *)rt_calloc(1, sizeof(struct finsh_shell)); if (shell == RT_NULL) { rt_kprintf("no memory for shell\n"); return -1; } tid = rt_thread_create(FINSH_THREAD_NAME, finsh_thread_entry, RT_NULL, FINSH_THREAD_STACK_SIZE, FINSH_THREAD_PRIORITY, 10);#else shell = &_shell; tid = &finsh_thread; result = rt_thread_init(&finsh_thread, FINSH_THREAD_NAME, finsh_thread_entry, RT_NULL, &finsh_thread_stack[0], sizeof(finsh_thread_stack), FINSH_THREAD_PRIORITY, 10);#endif /* RT_USING_HEAP */ rt_sem_init(&(shell->rx_sem), "shrx", 0, 0); finsh_set_prompt_mode(1); if (tid != NULL && result == RT_EOK) rt_thread_startup(tid); return 0;}INIT_APP_EXPORT(finsh_system_init);
转载地址:http://jdnii.baihongyu.com/