Rtthread线程源码分析
/*** This function will create a thread object and allocate thread object memory* and stack.** @param name the name of thread, which shall be unique* @param entry the entry function of thread* @param parameter the parameter of thread enter function* @param stack_size the size of thread stack* @param priority the priority of thread* @param tick the time slice if there are same priority thread** @return the created thread object*/
rt_thread_t rt_thread_create(const char *name,void (*entry)(void *parameter),void *parameter,rt_uint32_t stack_size,rt_uint8_t priority,rt_uint32_t tick)
{struct rt_thread *thread;void *stack_start;//1. 创建一个RT_Object_Class_Thread类型的objectd对象thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread,name);if (thread == RT_NULL)return RT_NULL;//2. 申请分配线程栈空间stack_start = (void *)RT_KERNEL_MALLOC(stack_size);if (stack_start == RT_NULL){/* allocate stack failure *///失败需要先删除该object并释放内存rt_object_delete((rt_object_t)thread);return RT_NULL;}//3. 调用_rt_thread_init_rt_thread_init(thread,name,entry,parameter,stack_start,stack_size,priority,tick);return thread;
}static rt_err_t _rt_thread_init(struct rt_thread *thread,const char *name,void (*entry)(void *parameter),void *parameter,void *stack_start,rt_uint32_t stack_size,rt_uint8_t priority,rt_uint32_t tick)
{/* init thread list */rt_list_init(&(thread->tlist));// 1. 指定线程入口函数和参数thread->entry = (void *)entry;thread->parameter = parameter;/* stack init *///2. 线程结构体初始化thread->stack_addr = stack_start;thread->stack_size = stack_size;/* init thread stack */rt_memset(thread->stack_addr, '#', thread->stack_size);
#ifdef ARCH_CPU_STACK_GROWS_UPWARD //我们一般使用满减栈,所以该宏不定义thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,(void *)((char *)thread->stack_addr),(void *)rt_thread_exit);
#else //走else// 3. 调用rt_hw_stack_init 初始化栈,栈顶的值为 【栈首地址 + 栈大小 - 4】thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,(rt_uint8_t *)((char *)thread->stack_addr + thread->stack_size - sizeof(rt_ubase_t)),(void *)rt_thread_exit);
#endif/* priority init */RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);//初始化thread优先级成员thread->init_priority = priority;thread->current_priority = priority;thread->number_mask = 0;
#if RT_THREAD_PRIORITY_MAX > 32thread->number = 0;thread->high_mask = 0;
#endif/* tick init */thread->init_tick = tick;thread->remaining_tick = tick;/* error and flags */thread->error = RT_EOK;thread->stat = RT_THREAD_INIT;/* initialize cleanup function and user data */thread->cleanup = 0;thread->user_data = 0;/* initialize thread timer *///初始化线程timerrt_timer_init(&(thread->thread_timer),thread->name,rt_thread_timeout,thread,0,RT_TIMER_FLAG_ONE_SHOT);RT_OBJECT_HOOK_CALL(rt_thread_inited_hook, (thread));return RT_EOK;
}
rt_uint8_t *rt_hw_stack_init(void *tentry,void *parameter,rt_uint8_t *stack_addr,void *texit)
{struct stack_frame *stack_frame;rt_uint8_t *stk;unsigned long i;stk = stack_addr + sizeof(rt_uint32_t);//传进来的stack_addr 减去了4,所以这里加上4stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);//向下8对齐,考虑到64bit平台stk -= sizeof(struct stack_frame);//偏移到stack_frame的首地址stack_frame = (struct stack_frame *)stk;/* init all register */for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++){((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;}//这些寄存器是线程调度时自动加载到寄存器中去的,剩下的r4-r11需要手动加载stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */stack_frame->exception_stack_frame.r1 = 0; /* r1 */stack_frame->exception_stack_frame.r2 = 0; /* r2 */stack_frame->exception_stack_frame.r3 = 0; /* r3 */stack_frame->exception_stack_frame.r12 = 0; /* r12 *//*线程函数退出时会执行,退出时会将该函数当作返回的地址*/stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR XPSR bit24 为1,使用thumb指令集*/#if USE_FPUstack_frame->flag = 0;
#endif /* USE_FPU *//* return task's current stack address */return stk;
}
栈初始化后的布局
rt_thread_startup
rt_thread_startup函数主要作用是将当前init完成的线程从SUSPEND状态切换到READY状态,
将该thread从tlist链表中移除,插入到就绪链表。
/*** This function will start a thread and put it to system ready queue** @param thread the thread to be started** @return the operation status, RT_EOK on OK, -RT_ERROR on error*/
rt_err_t rt_thread_startup(rt_thread_t thread)
{/* thread check */RT_ASSERT(thread != RT_NULL);RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT);RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);/* set current priority to initialize priority */thread->current_priority = thread->init_priority;/* calculate priority attribute */
#if RT_THREAD_PRIORITY_MAX > 32thread->number = thread->current_priority >> 3; /* 5bit */thread->number_mask = 1L << thread->number;thread->high_mask = 1L << (thread->current_priority & 0x07); /* 3bit */
#elsethread->number_mask = 1L << thread->current_priority;//计算当前number_mask
#endifRT_DEBUG_LOG(RT_DEBUG_THREAD, ("startup a thread:%s with priority:%d\n",thread->name, thread->init_priority));/* change thread stat */thread->stat = RT_THREAD_SUSPEND; //将init状态切换到SUSPEND状态/* then resume it */rt_thread_resume(thread); //调用resume将该thread切换到ready状态if (rt_thread_self() != RT_NULL)//开第一个系统线程的时候不会走这里{/* do a scheduling */rt_schedule();}return RT_EOK;
}
/*** This function will resume a thread and put it to system ready queue.** @param thread the thread to be resumed** @return the operation status, RT_EOK on OK, -RT_ERROR on error*/
rt_err_t rt_thread_resume(rt_thread_t thread)
{register rt_base_t temp;/* thread check */RT_ASSERT(thread != RT_NULL);RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: %s\n", thread->name));if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND){RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: thread disorder, %d\n",thread->stat));return -RT_ERROR;}/* disable interrupt */temp = rt_hw_interrupt_disable();/* remove from suspend list *///将该tlist从thread中移除rt_list_remove(&(thread->tlist));rt_timer_stop(&thread->thread_timer);/* enable interrupt */rt_hw_interrupt_enable(temp);/* insert to schedule ready list *///将该线程插入ready list,将tlist挂载到rt_thread_priority_table中去rt_schedule_insert_thread(thread);RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread));return RT_EOK;
}/*** @ingroup SystemInit* This function will startup scheduler. It will select one thread* with the highest priority level, then switch to it.*/
void rt_system_scheduler_start(void)
{register struct rt_thread *to_thread;register rt_ubase_t highest_ready_priority;#if RT_THREAD_PRIORITY_MAX > 32register rt_ubase_t number;number = __rt_ffs(rt_thread_ready_priority_group) - 1;highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
#else//快速查找最高优先级线程,时间复杂度固定的,RTOS系统关键部分highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
#endif/* get switch to thread */to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,struct rt_thread,tlist);rt_current_thread = to_thread;/* switch to new thread *///线程调度实现:rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);/* never come back */
}
/** void rt_hw_context_switch_to(rt_uint32 to);* r0 --> to*/
.global rt_hw_context_switch_to
.type rt_hw_context_switch_to, %function
rt_hw_context_switch_to://将rt_hw_context_switch_to的参数(rt_uint32_t)&to_thread->sp sp的地址保存到rt_interrupt_to_threadLDR r1, =rt_interrupt_to_threadSTR r0, [r1]#if defined (__VFP_FP__) && !defined(__SOFTFP__)/* CLEAR CONTROL.FPCA */MRS r2, CONTROL /* read */BIC r2, #0x04 /* modify */MSR CONTROL, r2 /* write-back */
#endif/* set from thread to 0 *///第一次切换线程,无需保存上文,rt_interrupt_from_thread写0LDR r1, =rt_interrupt_from_threadMOV r0, #0x0STR r0, [r1]/* set interrupt flag to 1 *///将rt_thread_switch_interrupt_flag 置1LDR r1, =rt_thread_switch_interrupt_flagMOV r0, #1STR r0, [r1]/* set the PendSV and SysTick exception priority *///将systick和pendsv优先级都设置为最低LDR r0, =NVIC_SYSPRI2LDR r1, =NVIC_PENDSV_PRILDR.W r2, [r0,#0x00] /* read */ORR r1,r1,r2 /* modify */STR r1, [r0] /* write-back *///写28bit 置1将悬起Pendsv中断,如果当前没有其他中断发生,那么将进入pendsv handlerLDR r0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */LDR r1, =NVIC_PENDSVSETSTR r1, [r0]/* restore MSP */LDR r0, =SCB_VTOR //获取SCB_VTOR寄存器的地址LDR r0, [r0] //获取SCB_VTOR寄存器的值,该值保存向量表的地址LDR r0, [r0] //获取向量表偏移为0的值,即为MSP指针(启动文件中向量表的排布)NOPMSR msp, r0 //复位MSP/* enable interrupts at processor level */CPSIE F //使能中断和异常CPSIE I/* never reach here! */
悬起一个pendsv异常后,在没有其他中断或者异常发生的时候,就会进入pendsv中切换上下文:
/* r0 --> switch from thread stack* r1 --> switch to thread stack* psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack*/
.global PendSV_Handler
.type PendSV_Handler, %function
PendSV_Handler:/* disable interrupt to protect context switch *///上下文切换之前先要禁用中断,保证切换不被打断MRS r2, PRIMASKCPSID I/* get rt_thread_switch_interrupt_flag *///判断rt_thread_switch_interrupt_flag,为0则退出pendsv handlerLDR r0, =rt_thread_switch_interrupt_flagLDR r1, [r0]CBZ r1, pendsv_exit /* pendsv already handled *//* clear rt_thread_switch_interrupt_flag to 0 *///清理rt_thread_switch_interrupt_flag MOV r1, #0x00STR r1, [r0]//判断是否需要保存上文,启动第一个线程的时候不需要保存上文。LDR r0, =rt_interrupt_from_threadLDR r1, [r0]CBZ r1, switch_to_thread /* skip register save at the first time *///保存上文:获取上文psp的值MRS r1, psp /* get from thread stack pointer */#if defined (__VFP_FP__) && !defined(__SOFTFP__)TST lr, #0x10 /* if(!EXC_RETURN[4]) */VSTMDBEQ r1!, {d8 - d15} /* push FPU register s16~s31 */
#endif//将R4-R11手动保存到栈中,其他寄存器都已经由硬件自动入栈保存了。//相当于: r1 -= 4*(11 - 4) for(i = 0; i < 11 - 4; i++) r4 -> r11 入栈STMFD r1!, {r4 - r11} /* push r4 - r11 register */#if defined (__VFP_FP__) && !defined(__SOFTFP__)MOV r4, #0x00 /* flag = 0 */TST lr, #0x10 /* if(!EXC_RETURN[4]) */MOVEQ r4, #0x01 /* flag = 1 */STMFD r1!, {r4} /* push flag */
#endif//更新栈变量的值为 当前栈指针指向的栈地址LDR r0, [r0]STR r1, [r0] /* update from thread stack pointer *///下文切换:
switch_to_thread://获取栈指针的值LDR r1, =rt_interrupt_to_threadLDR r1, [r1]LDR r1, [r1] /* load thread stack pointer */#if defined (__VFP_FP__) && !defined(__SOFTFP__)LDMFD r1!, {r3} /* pop flag */
#endif//手动将r4-r11出栈,写入对应的寄存器中。LDMFD r1!, {r4 - r11} /* pop r4 - r11 register */#if defined (__VFP_FP__) && !defined(__SOFTFP__)CMP r3, #0 /* if(flag_r3 != 0) */VLDMIANE r1!, {d8 - d15} /* pop FPU register s16~s31 */
#endif//将r1(当前栈地址) 写入psp, 在异常返回时硬件会主动Load r0 r1...这些寄存器MSR psp, r1 /* update stack pointer */#if defined (__VFP_FP__) && !defined(__SOFTFP__)ORR lr, lr, #0x10 /* lr |= (1 << 4), clean FPCA. */CMP r3, #0 /* if(flag_r3 != 0) */BICNE lr, lr, #0x10 /* lr &= ~(1 << 4), set FPCA. */
#endifpendsv_exit:/* restore interrupt */MSR PRIMASK, r2//在进入异常服务程序后,LR的值被自动更新为特殊的EXC_RETURN,这//是一个高28位全为1的值,只有[3:0]的值有特殊含义//bit2 == 1 从进程堆栈中做出栈操作,返回后使用PSPORR lr, lr, #0x04BX lr
到这里线程main线程就会开始启动了,启动之后,systick定时器会在各个线程时间片耗尽之后触发pendsv切换
线程。
void SysTick_Handler(void)
{/* enter interrupt */rt_interrupt_enter();rt_tick_increase();/* leave interrupt */rt_interrupt_leave();
}
/*** This function will notify kernel there is one tick passed. Normally,* this function is invoked by clock ISR.*/
void rt_tick_increase(void)
{struct rt_thread *thread;/* increase the global tick */++ rt_tick;//计时器+1 单位ms/* check time slice */thread = rt_thread_self();//获取当前线程-- thread->remaining_tick;//线程时间片-1if (thread->remaining_tick == 0)//时间片耗尽{/* change to initialized tick */thread->remaining_tick = thread->init_tick;//时间片重新赋值/* yield */rt_thread_yield();//线程挂起}/* check timer */rt_timer_check();
}
/*** This function will let current thread yield processor, and scheduler will* choose a highest thread to run. After yield processor, the current thread* is still in READY state.** @return RT_EOK*/
rt_err_t rt_thread_yield(void)
{register rt_base_t level;struct rt_thread *thread;/* disable interrupt */level = rt_hw_interrupt_disable();/* set to current thread */thread = rt_current_thread;/* if the thread stat is READY and on ready queue list */if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY &&thread->tlist.next != thread->tlist.prev)//线程时ready状态并且挂载在就绪表中{/* remove thread from thread list */rt_list_remove(&(thread->tlist));/* put thread to end of ready queue */rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),&(thread->tlist));//将当前线程插入末尾/* enable interrupt */rt_hw_interrupt_enable(level);rt_schedule();//开启线程调度return RT_EOK;}/* enable interrupt */rt_hw_interrupt_enable(level);return RT_EOK;
}/*** This function will perform one schedule. It will select one thread* with the highest priority level, then switch to it.*/
void rt_schedule(void)
{rt_base_t level;struct rt_thread *to_thread;struct rt_thread *from_thread;/* disable interrupt */level = rt_hw_interrupt_disable();/* check the scheduler is enabled or not */if (rt_scheduler_lock_nest == 0)//rt_scheduler_lock_nest 用来锁住rt_schedule,确保有些场景不能被打断{register rt_ubase_t highest_ready_priority;#if RT_THREAD_PRIORITY_MAX <= 32//获取就绪表中优先级最高的线程下标highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
#elseregister rt_ubase_t number;number = __rt_ffs(rt_thread_ready_priority_group) - 1;highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
#endif/* get switch to thread *///获取将要切换的线程实例to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,struct rt_thread,tlist);/* if the destination thread is not the same as current thread */if (to_thread != rt_current_thread){rt_current_priority = (rt_uint8_t)highest_ready_priority;from_thread = rt_current_thread;rt_current_thread = to_thread;RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (from_thread, to_thread));/* switch to new thread */RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,("[%d]switch to priority#%d ""thread:%.*s(sp:0x%p), ""from thread:%.*s(sp: 0x%p)\n",rt_interrupt_nest, highest_ready_priority,RT_NAME_MAX, to_thread->name, to_thread->sp,RT_NAME_MAX, from_thread->name, from_thread->sp));#ifdef RT_USING_OVERFLOW_CHECK_rt_scheduler_stack_check(to_thread);
#endifif (rt_interrupt_nest == 0){rt_hw_context_switch((rt_ubase_t)&from_thread->sp,(rt_ubase_t)&to_thread->sp);/* enable interrupt */rt_hw_interrupt_enable(level);return ;}else{RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("switch in interrupt\n"));rt_hw_context_switch_interrupt((rt_ubase_t)&from_thread->sp,(rt_ubase_t)&to_thread->sp);}}}/* enable interrupt */rt_hw_interrupt_enable(level);
}
/** void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);* r0 --> from* r1 --> to*/
.global rt_hw_context_switch_interrupt
.type rt_hw_context_switch_interrupt, %function
.global rt_hw_context_switch
.type rt_hw_context_switch, %functionrt_hw_context_switch_interrupt:
rt_hw_context_switch:/* set rt_thread_switch_interrupt_flag to 1 */LDR r2, =rt_thread_switch_interrupt_flagLDR r3, [r2]CMP r3, #1BEQ _reswitch //判断rt_thread_switch_interrupt_flag是否为1,为1说明上一次线程切换没有完成,跳转到_reswitch MOV r3, #1 //rt_thread_switch_interrupt_flag 为0,将其置1STR r3, [r2]LDR r2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */STR r0, [r2] //将上文中的栈指针的地址保存到rt_interrupt_from_thread _reswitch:LDR r2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */STR r1, [r2] //将下文中的栈指针地址保存到rt_interrupt_to_thread LDR r0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */LDR r1, =NVIC_PENDSVSET STR r1, [r0] //悬起pendsvBX LR //异常返回
线程退出
当线程函数退出时会将lr的值load到pc中,因为在初始化线程栈时,LR的值我们设置的是rt_thread_exit,所以
线程函数退出时会call这个函数。
void rt_thread_exit(void)
{struct rt_thread *thread;register rt_base_t level;/* get current thread */thread = rt_current_thread;//获取当前退出的线程/* disable interrupt */level = rt_hw_interrupt_disable();_thread_cleanup_execute(thread);//如果有指定该线程的清理函数,则会调用该线程的清理函数/* remove from schedule */rt_schedule_remove_thread(thread);//将该线程从就绪表中移除/* change stat */thread->stat = RT_THREAD_CLOSE;//设置线程状态为close/* remove it from timer list */rt_timer_detach(&thread->thread_timer);//线程时间分离if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE)//判断是否为系统线程{rt_object_detach((rt_object_t)thread);//将系统线程从object管理系统中移除}else//非系统线程(动态申请内存)直接插入到僵尸列表{/* insert to defunct thread list */rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));//非系统线程则丢到僵尸线程表中}/* switch to next task */rt_schedule();//呼叫线程调度/* enable interrupt */rt_hw_interrupt_enable(level);
}
线程分离/删除
线程分离和线程删除函数差别如下:
线程分离函数可以将静态线程从object中移除,线程删除函数则只能将动态分配的线程移除到僵尸线程表中
/*** This function will detach a thread. The thread object will be removed from* thread queue and detached/deleted from system object management.** @param thread the thread to be deleted** @return the operation status, RT_EOK on OK, -RT_ERROR on error*/
rt_err_t rt_thread_detach(rt_thread_t thread)
{rt_base_t lock;/* thread check */RT_ASSERT(thread != RT_NULL);RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);//线程对象RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread));//这个判断不对,RT_ASSERT宏默认关if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)return RT_EOK;if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT){/* remove from schedule */rt_schedule_remove_thread(thread);//从就绪表中移除}_thread_cleanup_execute(thread);//线程清理/* release thread timer */rt_timer_detach(&(thread->thread_timer));/* change stat */thread->stat = RT_THREAD_CLOSE;//改变线程状态if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE){rt_object_detach((rt_object_t)thread);//栈中分配的线程直接从object管理表中移除}else{/* disable interrupt */lock = rt_hw_interrupt_disable();/* insert to defunct thread list */rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));//动态分配的线程移除到僵尸列表中/* enable interrupt */rt_hw_interrupt_enable(lock);}return RT_EOK;
}/*** This function will delete a thread. The thread object will be removed from* thread queue and deleted from system object management in the idle thread.** @param thread the thread to be deleted** @return the operation status, RT_EOK on OK, -RT_ERROR on error*/
rt_err_t rt_thread_delete(rt_thread_t thread)
{rt_base_t lock;/* thread check */RT_ASSERT(thread != RT_NULL);RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread) == RT_FALSE);if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)return RT_EOK;if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT){/* remove from schedule */rt_schedule_remove_thread(thread);}_thread_cleanup_execute(thread);/* release thread timer */rt_timer_detach(&(thread->thread_timer));/* disable interrupt */lock = rt_hw_interrupt_disable();/* change stat */thread->stat = RT_THREAD_CLOSE;/* insert to defunct thread list */rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));/* enable interrupt */rt_hw_interrupt_enable(lock);return RT_EOK;
}
#endif
线程定时
/*** This function will let current thread sleep for some ticks.** @param tick the sleep ticks** @return RT_EOK*/
rt_err_t rt_thread_sleep(rt_tick_t tick)
{register rt_base_t temp;struct rt_thread *thread;/* disable interrupt */temp = rt_hw_interrupt_disable();/* set to current thread */thread = rt_current_thread;RT_ASSERT(thread != RT_NULL);RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);/* suspend thread */rt_thread_suspend(thread);//挂起该线程/* reset the timeout of thread timer and start it */rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);//设置挂起时间rt_timer_start(&(thread->thread_timer));//开始计时/* enable interrupt */rt_hw_interrupt_enable(temp);rt_schedule();//线程调度/* clear error number of this thread to RT_EOK */if (thread->error == -RT_ETIMEOUT)thread->error = RT_EOK;return RT_EOK;
}
/*** This function will suspend the specified thread.** @param thread the thread to be suspended** @return the operation status, RT_EOK on OK, -RT_ERROR on error** @note if suspend self thread, after this function call, the* rt_schedule() must be invoked.*/
rt_err_t rt_thread_suspend(rt_thread_t thread)
{register rt_base_t temp;/* thread check */RT_ASSERT(thread != RT_NULL);RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: %s\n", thread->name));if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY){RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: thread disorder, 0x%2x\n",thread->stat));return -RT_ERROR;}/* disable interrupt */temp = rt_hw_interrupt_disable();/* change thread stat */rt_schedule_remove_thread(thread);//将该线程从就绪表中移除thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK);//将状态设置为RT_THREAD_SUSPEND /* stop thread timer anyway */rt_timer_stop(&(thread->thread_timer));//停止计时/* enable interrupt */rt_hw_interrupt_enable(temp);RT_OBJECT_HOOK_CALL(rt_thread_suspend_hook, (thread));return RT_EOK;
}
/*** This function will control thread behaviors according to control command.** @param thread the specified thread to be controlled* @param cmd the control command, which includes* RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread;* RT_THREAD_CTRL_STARTUP for starting a thread;* RT_THREAD_CTRL_CLOSE for delete a thread;* RT_THREAD_CTRL_BIND_CPU for bind the thread to a CPU.* @param arg the argument of control command** @return RT_EOK*/
rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg)
{register rt_base_t temp;/* thread check */RT_ASSERT(thread != RT_NULL);RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);switch (cmd){case RT_THREAD_CTRL_CHANGE_PRIORITY: //改变线程优先级/* disable interrupt */temp = rt_hw_interrupt_disable();/* for ready thread, change queue */if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY) //线程在就绪表中{/* remove thread from schedule queue first */rt_schedule_remove_thread(thread); //先将该线程移除/* change thread priority */thread->current_priority = *(rt_uint8_t *)arg; //修改线程优先级/* recalculate priority attribute */
#if RT_THREAD_PRIORITY_MAX > 32thread->number = thread->current_priority >> 3; /* 5bit */thread->number_mask = 1 << thread->number;thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */
#elsethread->number_mask = 1 << thread->current_priority;//设置优先级mask
#endif/* insert thread to schedule queue again */rt_schedule_insert_thread(thread);//修改好优先级后重新插入线程表}else //线程未在就绪表中{thread->current_priority = *(rt_uint8_t *)arg;/* recalculate priority attribute */
#if RT_THREAD_PRIORITY_MAX > 32thread->number = thread->current_priority >> 3; /* 5bit */thread->number_mask = 1 << thread->number;thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */
#elsethread->number_mask = 1 << thread->current_priority;
#endif}/* enable interrupt */rt_hw_interrupt_enable(temp);break;case RT_THREAD_CTRL_STARTUP://启动线程return rt_thread_startup(thread);case RT_THREAD_CTRL_CLOSE://关闭线程/分离线程if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE)//静态线程使用detech{return rt_thread_detach(thread);}
#ifdef RT_USING_HEAPelse //动态线程使用delete{return rt_thread_delete(thread);}
#endifdefault:break;}return RT_EOK;
}
/*** This function will lock the thread scheduler.*/
//该函数会使rt_scheduler_lock_nest ++,从而锁住scheduler,确保在解锁之前当前代码段不会被scheduler中断执行
void rt_enter_critical(void)
{register rt_base_t level;/* disable interrupt */level = rt_hw_interrupt_disable();/** the maximal number of nest is RT_UINT16_MAX, which is big* enough and does not check here*/rt_scheduler_lock_nest ++;/* enable interrupt */rt_hw_interrupt_enable(level);
}/*** This function will unlock the thread scheduler.*/
void rt_exit_critical(void)
{register rt_base_t level;/* disable interrupt */level = rt_hw_interrupt_disable();rt_scheduler_lock_nest --;if (rt_scheduler_lock_nest <= 0){rt_scheduler_lock_nest = 0;/* enable interrupt */rt_hw_interrupt_enable(level);if (rt_current_thread){/* if scheduler is started, do a schedule *///这里因为如果线程systic timer超时了,本来需要做rt_schedule,但是因为rt_schedule被锁住,而没有做//所以会在解锁后做一次,如果该线程确实超时,那么就会执行shedule,线程时间片还没耗尽的话,因为它的优先级是排在//最前的,所以rt_schedule中会有判断当前from和to的线程是一致的,就不会切换。rt_schedule();}}else{/* enable interrupt */rt_hw_interrupt_enable(level);}
}
/*** This function is the timeout function for thread, normally which is invoked* when thread is timeout to wait some resource.** @param parameter the parameter of thread timeout function*/
void rt_thread_timeout(void *parameter)
{struct rt_thread *thread;thread = (struct rt_thread *)parameter;/* thread check */RT_ASSERT(thread != RT_NULL);RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND);RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);/* set error number */thread->error = -RT_ETIMEOUT;/* remove from suspend list */rt_list_remove(&(thread->tlist));//do nothing/* insert to schedule ready list */rt_schedule_insert_thread(thread);//将线程插入到就绪表/* do schedule */rt_schedule();
}/*** This function will find the specified thread.** @param name the name of thread finding** @return the found thread** @note please don't invoke this function in interrupt status.*/
rt_thread_t rt_thread_find(char *name)
{return (rt_thread_t)rt_object_find(name, RT_Object_Class_Thread);
}
Rtthread thread 内部timer作用:
thread结构体中包含一个timer成员:
struct rt_timer thread_timer; /**< built-in thread timer */
在init_thread函数里面会对其进行初始化:
/* initialize thread timer */rt_timer_init(&(thread->thread_timer),thread->name,rt_thread_timeout,thread,0,RT_TIMER_FLAG_ONE_SHOT);
这里设置的超时回调函数为rt_thread_timeout,初始超时时间为0,RT_TIMER_FLAG_ONE_SHOT
为单次定时事件。
再看看rt_thread_timeout实现:
定时时间超时的时候会调用该函数,函数参数为该线程的信息。
主要做了如下操作:
1.设置thread->error 为 -RT_ETIMEOUT
2.移除当前线程节点
3.将该线程再次插入到就绪列表
4.执行线程调度
void rt_thread_timeout(void *parameter)
{struct rt_thread *thread;thread = (struct rt_thread *)parameter;/* thread check */RT_ASSERT(thread != RT_NULL);RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND);RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);/* set error number */thread->error = -RT_ETIMEOUT;///* remove from suspend list */rt_list_remove(&(thread->tlist));/* insert to schedule ready list */rt_schedule_insert_thread(thread);/* do schedule */rt_schedule();
}
那么什么时候会执行上述超时函数呢?
答案是在调用rt_thread_delay(rt_tick_t tick)的时候,rt_thread_delay会调用rt_thread_sleep
调用rt_thread_sleep的时候,函数执行下面的动作:
1.先调用rt_thread_suspend(thread)将当前线程休眠,移出就绪表。
2.调用rt_timer_control设置定时时间(休眠时间)。
3.调用rt_timer_start开启定时。
4.因为当前线程已经休眠,所以需要调用rt_schedule()调度到新的线程执行。
5.将thread->error = RT_EOK
rt_err_t rt_thread_delay(rt_tick_t tick)
{return rt_thread_sleep(tick);
}
rt_err_t rt_thread_sleep(rt_tick_t tick)
{register rt_base_t temp;struct rt_thread *thread;/* disable interrupt */temp = rt_hw_interrupt_disable();/* set to current thread */thread = rt_current_thread;RT_ASSERT(thread != RT_NULL);RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);/* suspend thread */rt_thread_suspend(thread);/* reset the timeout of thread timer and start it */rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);rt_timer_start(&(thread->thread_timer));/* enable interrupt */rt_hw_interrupt_enable(temp);rt_schedule();/* clear error number of this thread to RT_EOK */if (thread->error == -RT_ETIMEOUT)thread->error = RT_EOK;return RT_EOK;
}
这样当线程delay或者休眠时就会让出cpu,并在休眠时间到达目标值时通过rt_thread_timeout执行新的
调度。
rt_tick_increase函数会在systick中断中被调用,每次调用都会调用timer模块的rt_timer_check函数检查
是否有新的超时事件.
当线程被调用detech或者delete的时候,线程的detech/delete函数也会分别调用线程timer的detech/delete,
将该timer从object中移除。