rt_thread nano移植finsh控制台输入线程finsh_thread_entry无法执行的问题

本文详细解析了RT-Thread操作系统中main线程的执行流程,以及Finsh Shell的初始化过程。在RT-Thread中,main函数被包装为一个线程执行,并通过信号量管理与其他线程的交互。Finsh Shell的初始化涉及符号表的设置和线程创建,其线程优先级的设定对于系统运行至关重要。文章探讨了线程优先级调整可能导致的问题,强调了正确的线程管理和调度对系统稳定性的影响。
摘要由CSDN通过智能技术生成

根据官方文档推荐,我们需要在接收中断中释放信号量让finsh线程读取,而没有信号量的时候

在keil中的拓展函数功能$$sub$ $$super$

先看一下关于$$Super$和$$Sub$的意思:$$Sub$function用于替代原本的function函数,再使用$$Super$跳转到原函数,这样就可以实现原函数不变的情况下在函数前后增添语句,比如这样

int $$Sub%main(void)
{
    printf("now entry\n");
    $$Super$main();
    printf("now leave\n");
}

rt_thread通过这样的方式在main函数前拓展了系统的初始化,相关代码在components.c 140行,隐去了无关和未编译代码段

int $Sub$$main(void)
{
    rtthread_startup();
    return 0;
}


/* the system main thread *///main线程
void main_thread_entry(void *parameter)
{
    extern int main(void);
    extern int $Super$$main(void);

#ifdef RT_USING_COMPONENTS_INIT
    /* RT-Thread components initialization */
    rt_components_init();
#endif
    /* invoke system main function */
#if defined(__CC_ARM) || defined(__CLANG_ARM)
    $Super$$main(); /* for ARMCC. *///main函数在此执行
#elif defined(__ICCARM__) || defined(__GNUC__)
    main();
#endif
}

void rt_application_init(void)
{
    rt_thread_t tid;

#ifdef RT_USING_HEAP//如果使用动态内存,动态创建main线程
    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_thread_startup(tid);
}

int rtthread_startup(void)
{
    rt_hw_interrupt_disable();

    /* board level initialization
     * NOTE: please initialize heap inside board initialization.
     */
    rt_hw_board_init();            //board.c中的初始化

    /* show RT-Thread version */
    rt_show_version();

    /* timer system initialization */
    rt_system_timer_init();

    /* scheduler system initialization */
    rt_system_scheduler_init();

    /* create init_thread */
    rt_application_init();        //初始化main线程

    /* timer thread initialization */
    rt_system_timer_thread_init();

    /* idle thread initialization */
    rt_thread_idle_init();        //初始化空闲线程

    /* start scheduler */
    rt_system_scheduler_start(); //开启调度

    /* never reach here */
    return 0;
}

发现了吗?在freertos里面开启scheduler调度后不会再执行下去而是跳到各线程中去执行,rt-thread则是将main函数以一个线程在执行,其实我很好奇这样的main线程的结尾是没有死循环的,入口函数执行完后会发生什么?这部分申请的内存会回收掉吗?在这个main执行的过程中创建其他线程时,如果创建启动的线程比main线程优先级高,是不是直接就打断了main线程开始执行,这样不会造成线程执行顺序混乱吗?一般在freertos里,要么是挂载完所有线程再启动调度,要么就是在一个最高优先级的线程中开启其他线程,最后再删除自己,让其他任务得以开始执行。

下面是官方文档里的启动流程 

再让我们看一下finsh初始化函数 finsh_system_init

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线程
                           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);//就绪finsh线程
    return 0;
}
INIT_APP_EXPORT(finsh_system_init);

应该是挂载在rt_application_init()这个点(具体export用法没有细究,有空再学习)

那么现在就有一个特别有意思的地方,在开启调度前,有三个线程就绪 finsh,idle,main

让我们来看一下优先级吧

 

 

也就是说必须要main>finsh>idle才能正确执行,如果你像我一样调整了优先级那么很有可能出现两种情况:1.rt_thread_priority_max设小了,finsh<idle直接被idle饿死,2.在finshconfig.h更改了finsh的优先级,main函数优先级低于执行finsh执行,因为信号量必须在系统调度启动以后才能申请,如果信号量在main里面申请的话,申请之前就会被finsh 获取,然后finsh就永久挂起了

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值