Rtthread线程源码分析

article/2025/8/25 21:57:33

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中移除。


http://chatgpt.dhexx.cn/article/9cdkAWV1.shtml

相关文章

rtthread套娃移植

和大家分享下将基于rtthread的项目移植到其他平台的经验。 背景 最近做了一个物联网项目移植。原先的项目使用的硬件平台为stm32f401sim800c(mcu 2G modem)&#xff0c;软件平台为rtthread 4.0.1。移植到的新平台为BC25(nb modem)&#xff0c;软件平台为BC25 opencpu sdk&am…

关于RT thread系统节拍时钟的配置

关于RT thread系统节拍时钟的配置 -----本文基于rt-thread-3.1.3版本编写 首先&#xff0c;使用RTthread OS时&#xff0c;要配置&#xff08;或者明白&#xff09;它的系统节拍rt_tick&#xff08;划重点&#xff09;。 系统节拍 系统节拍是特定的周期中断&#xff0c;可以…

rtthread学习

RT-Thread 内核实现与应用开发实战指南 1、数据类型rtdef.h 中的数据类型 在裸机系统中&#xff0c;他们统统放在一个叫栈的地方&#xff0c;栈是单片机 RAM 里面一段连续的内存空间&#xff0c;栈的大小一般在启动文件或者链接脚本里面指定&#xff0c; 最后由 C 库函数_m…

Rtthread 内存管理

Rtthread 堆内存管理 #define HEAP_MAGIC 0x1ea0 struct heap_mem {/* magic and used flag */rt_uint16_t magic; //魔数&#xff0c;固定值rt_uint16_t used; //使用标记&#xff0c;1为该内存已经被使用rt_size_t next, prev; //双向链表偏移 }; #define MIN_SIZE 12 //一…

RT-Thread学习

一、入门 RT-Thread官网  官网文档   Rt-thread学习文档  RT-Thread官方bilibili视频号   GD32官网 教你动手移植RT-Thread到国产MCU    如何移植RT-Thread到GD32单片机上&#xff08;非studio版&#xff09; 东方青讲RT-Thread  RT-Thread内核入门指南 RT-Thread…

RT Thread之ADC电压读取

官网连接&#xff1a;https://docs.rt-thread.org/#/rt-thread-version/rt-thread-standard/programming-manual/device/adc/adc 一、配置步骤&#xff1a; 1、用cubemx配置底层&#xff1b; 2、cubemx配置好的文件替换之前的配置文件&#xff1b; 3、修改Kconfig文件&…

rtthread mqtt

rtthread 以太网 (LAN8720A) 基于以太网的应用mqtt&#xff0c;在**rtthread 以太网 (LAN8720A)**中已经实现了tcp/ip通信正常&#xff0c;接下需要启用mqtt模块&#xff0c; 嵌入式mqtt设备 rtthread 启用mqtt 在rtthread中田间 pahomqtt 软件包&#xff0c;并右键详细配置…

【RTThread】修改Finsh打印串口波特率

这里需要注意得是一定要在hw_board_init初始化完成之后修改串口波特率。 /* 串口设备句柄 */static rt_device_t uart_device RT_NULL;/* 查找系统中的串口设备 */uart_device rt_device_find("uart1"); // 这里/* 串口配置结构体&#xff0c;使用serial.h的宏定义…

RT Thread之 Uart2 操作

官网连接&#xff1a;https://docs.rt-thread.org/#/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart 通过前面的学习&#xff0c;基本上RT Thread操作步骤都是&#xff0c;先配置单片机底层&#xff0c;然后再通过应用层映射到底层&#xff0c;最…

rtthread

链表 初始化双向链表 rt_inline void rt_list_init(rt_list_t *l) {l->next l->prev l; }插入 rt_inline void rt_list_insert_after(rt_list_t *l, rt_list_t *n) {l->next->prev n;n->next l->next;l->next n;n->prev l; }在NODE1后面插入节…

RT Thread根据开发板制作BSP方法

之前一直不懂怎么使用RT Thread的软件包&#xff0c;感谢网上的大神&#xff0c;看了你们的博客后大概了解一些&#xff0c;在此做下记录。用RT Thread软件包需要RT Thread的系统&#xff0c;但是RT Thread和RT Thread nano不一样&#xff0c;具体区别见 RT Thread官网&#xf…

rtthread开关中断

1 rtthread开关中断函数(cortex-m) /** rt_base_t rt_hw_interrupt_disable();*/ .global rt_hw_interrupt_disable .type rt_hw_interrupt_disable, %function rt_hw_interrupt_disable:MRS r0, PRIMASKCPSID IBX LR/** void rt_hw_interrupt_enable(rt_base_t le…

RTThread入门

RT-Thread入门 1.初识RT-Thread 嵌入式系统是一种完全嵌入在装置或设备内部&#xff0c;为满足特定需求而设计的计算机系统&#xff0c;譬如生活中常见的嵌入式系统就有&#xff1a;电视机顶盒、路由器、电冰箱、微波炉与移动电话等。 嵌入式操作系统是应用于嵌入式系统的软…

什么是RT-Thread?

一、RT-Thread的定义 RT-Thread&#xff0c;全称是 Real Time-Thread&#xff0c; 是一款主要由中国开源社区主导开发的开源实时操作系统&#xff08;许可证GPLv2&#xff09;&#xff0c;包含了实时、嵌入式系统相关的各个组件&#xff1a;TCP/IP协议栈、图形用户界面等。 相…

Redis启动失败的原因及解决方法

跑了近半年的Redis,今天早上来开启电脑运行程序的时候发现提示无法连接redis,暗想自己明明设置了开机自启的阿,以前也一直没问提,今天怎么就连不上了重启了下redis就提示如下错误 网上搜了好久都没找到解决办法,后来想起来去查看了下redis的日志文件 发现提示当前版本的redis无…

redis启动、获取密码及修改密码

一、启动redis服务的两种方式 查看密码是以redis服务已启动的前提下进行的&#xff0c;可直接在服务中右键启动redis或者安装根目录运行cmd输入《redis-server.exe》(不推荐不推荐不推荐&#xff0c;说三遍&#xff0c;命令行启动好像有bug&#xff0c;启动后redis能用&#x…

CentOS安装Redis及redis启动与关闭、配置(详细)

在项目使用redis过程中&#xff0c;在centos7上部署redis&#xff0c;查找相关资料并总结、记录&#xff0c;以备后续查看。 目录 一、Redis介绍 二、在CentOS上部署Redis 1、Redis安装包可以从官网上下载或者直接命令下载 升级到gcc 9.3&#xff1a; 3、Redis配置文件…

Redis启动和连接

一&#xff09;Redis简介 Redis不是简单的键值存储&#xff0c;它实际上是一个数据结构服务器&#xff0c;支持不同类型的值。 备注&#xff1a;由于我电脑是32位操作系统&#xff0c;所有就不提供redis软件下载地址了&#xff0c;请到官网下载使用。 软件解压之后&#xff0…

windows下Redis启动闪退问题解决经验汇总

最近使用Redis又遇到启动闪退的问题&#xff0c;之前记录的解决办法也失败了&#xff0c;一番研究后总算得到解决&#xff0c;感觉已经遇到了网上常见的各种问题&#xff0c;下面总结下。 我下载的是免安装版&#xff0c;解压便可使用。 官网下载传送门&#xff1a;Releases …

Windows下redis启动那些事儿

本文章主要描述我遇到的Windows下redis启动成功但Java项目无法连接问题 1.使用redis可视化工具可以连接&#xff0c;但是到Java项目中就报错连接失败 经过我的多方琢磨&#xff0c;还是密码没有配置正确&#xff0c;虽然是在redis.windows.conf配置文件中配置了 requirepass 密…