前言
本章以MDK-ARM为例,通常我们编写裸机程序,程序会先执行一段汇编代码(启动文件),然后由启动文件跳转到我们所熟知的main()函数,也就是说在裸机系统中,main()函数,是我们程序执行的第一个C函数,但是带rtthread的程序,执行的第一个C函数却不是main()函数。
一、__mian函数
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
在裸机系统中,程序执行完__main函数会跳转到C中的main函数
在rtthread工程中,程序执行完__main函数并不是跳转到C中的main函数,而是跳转到conmponent.c中的$Sub$$main
函数,这是为什么?因为 RT-Thread 使用编译器(这里指的是 KEIL)自带的 $Sub$$ 和 $Super$$这两个符号来扩展
了main 函数,使用 $Sub$$main 可以在执行 main 之前先执行 $Sub$$main,在$Sub$$main 函数中我们可以先执行一
些预操作,当做完这些预操作之后最终还是要执行 main 函数,这个就通过调用 $Super$$main 来实现。
二、$ Sub$$main函数
int $Sub$$main(void)
{
rtthread_startup();
return 0;
}
三、rtthread_startup函数
int rtthread_startup(void)
{
/* 关中断 */
rt_hw_interrupt_disable();
/* 板级硬件初始化 */
rt_hw_board_init();
/* 展示RT-Thread 的一些打印信息 */
rt_show_version();
/* 系统时钟初始化 */
rt_system_timer_init();
/* 系统调度器的初始化 */
rt_system_scheduler_init();
#ifdef RT_USING_SIGNALS
/* 如果define了RT_USING_SIGNALS,执行信号的初始化 */
rt_system_signal_init();
#endif /* RT_USING_SIGNALS */
/* 创建一个线程,这个线程最终会执行C中的main函数 */
rt_application_init();
/* 定时器线程的初始化 */
rt_system_timer_thread_init();
/* 空闲线程的初始化 */
rt_thread_idle_init();
/* 如果define 了RT_USING_SMP,关中断 */
#ifdef RT_USING_SMP
/* 关中断 */
rt_hw_spin_lock(&_cpus_lock);
#endif /* RT_USING_SMP */
/* 启动系统调度器 */
rt_system_scheduler_start();
/* never reach here */
return 0;
}
四、rt_application_init函数
void rt_application_init(void)
{
rt_thread_t tid;
#ifdef RT_USING_HEAP
tid = rt_thread_create("main", main_thread_entry, RT_NULL,
RT_MAIN_THREAD_STACK_SIZE, RT_MAIN_THREAD_PRIORITY, 20);
RT_ASSERT(tid != RT_NULL);
#else
rt_err_t result;
tid = &main_thread;
result = rt_thread_init(tid, "main", main_thread_entry, RT_NULL,
main_stack, sizeof(main_stack), RT_MAIN_THREAD_PRIORITY, 20);
RT_ASSERT(result == RT_EOK);
/* if not define RT_USING_HEAP, using to eliminate the warning */
(void)result;
#endif /* RT_USING_HEAP */
rt_thread_startup(tid);
}
这个函数创建了一个main_thread_entry线程,执行完这个线程,程序会跳转到C中的main函数
总结
rtthread工程启动流程,启动文件—》__main函数—》$ Sub$$main函数—》rtthread_startup函数—》启动调度器—》跳转到C中main函数