根据官方文档推荐,我们需要在接收中断中释放信号量让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就永久挂起了