RT-Thread 学习记录之内核启动流程

RT-Thread 学习记录之内核启动流程

内核简介

内核是学习 RT-Thread 最基础,也是最重要的部分。RT-Thread 中,内核处于硬件层之上,内核部分包括内核库、实时内核实现。

内核框架

从上图可知,RT-Thread 内核库中包含了对象管理、实时调度器、线程管理、线程通信、时钟管理、内存管理、设备管理等功能实现的相关源码。

这些后面都会做相对应的专题分析,首先我们应该先了解 RT-Thread 的启动流程。

启动顺序

以 CH32V307 开发板为例,通过调试功能进入启动,可整理出如下顺序:
启动顺序

可知,开发板上电后,执行启动文件 .S 的内容进行必要的初始化,之后进入 int entry(void) 这个函数(由于该开发板环境使用 GCC 编译,并未进入 S u b Sub Sub$main 函数),之后由这个函数跳入 rtthread_startup() 函数进行 RT-Thread 系统的初始化和启动。在执行完 rtthread_startup() 函数后,会创建 main 线程,并开启任务调度器,由此进入 main.c 中的用户主函数。

源码简析

首先对 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
    /* signal system initialization */
    rt_system_signal_init();
#endif /* RT_USING_SIGNALS */

    /* 创建原始线程, main 线程 */
    rt_application_init();

    /* 创建定时器线程 */
    rt_system_timer_thread_init();

    /* 创建空闲线程 */
    rt_thread_idle_init();

/* 判断是否使用多核处理器,由此选择是否初始化 */
#ifdef RT_USING_SMP
    rt_hw_spin_lock(&_cpus_lock);
#endif /* RT_USING_SMP */

    /* 启动调度器 */
    rt_system_scheduler_start();

    /* 永不抵达 */
    return 0;
}

rtthread_startup 函数进行简单分析可知,在该函数中,RT-Thread 完成了对整个系统内核的初始化以及调度器的启动。

接下来跳过各种内核初始化后对 rt_application_init 函数进行分析:

void rt_application_init(void)
{
    rt_thread_t tid;//线程句柄
/* 创建/初始化 main 线程 */
#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);//动态创建 main 线程
#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);//静态初始化 main 线程

    /* if not define RT_USING_HEAP, using to eliminate the warning */
    (void)result;
#endif /* RT_USING_HEAP */

    rt_thread_startup(tid);//启动 main 线程
}

rt_application_init 函数中,系统创建并启动了 main 线程,其入口函数是 main_thread_entry

void main_thread_entry(void *parameter)
{
    extern int main(void);//声明 main 函数

/* 初始化系统组件 */
#ifdef RT_USING_COMPONENTS_INIT
    /* RT-Thread components initialization */
    rt_components_init();
#endif /* RT_USING_COMPONENTS_INIT */

/* 判断是否使用多核 */
#ifdef RT_USING_SMP
    rt_hw_secondary_cpu_up();
#endif /* RT_USING_SMP */
    /* invoke system main function */
#ifdef __ARMCC_VERSION
    {
        extern int $Super$$main(void);
        $Super$$main(); /* for ARMCC. */
    }
#elif defined(__ICCARM__) || defined(__GNUC__) || defined(__TASKING__)
    main();//进入 main 函数
#endif
}

可知在这一步进行了主函数的调用。

总结

以上是 RT-Thread 的内核启动流程,在不同的芯片间大同小异,比如在 STM32 系列单片机中,进入 rtthread_startup 函数的入口为 $Sub $ $main 函数,而不是 int entry(void) 这个函数,其主要原因是编译链的不同,在通常使用 STM32 系列芯片时是使用 MDKARMCC 编译链进行编译的,而我手里这款 CH32V307 采用的是 GCC 编译链。

RT-Thread 支持多种平台和多种编译器,而 rtthread_startup() 函数是 RT-Thread 规定的统一启动入口

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值