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 > 32
thread->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 */
//初始化线程timer
rt_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,所以这里加上4
stk = (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_FPU
stack_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 > 32
thread->number = thread->current_priority >> 3; /* 5bit */
thread->number_mask = 1L << thread->number;
thread->high_mask = 1L << (thread->current_priority & 0x07); /* 3bit */
#else
thread->number_mask = 1L << thread->current_priority;//计算当前number_mask
#endif
RT_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 > 32
register 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_thread
LDR r1, =rt_interrupt_to_thread
STR 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写0
LDR r1, =rt_interrupt_from_thread
MOV r0, #0x0
STR r0, [r1]
/* set interrupt flag to 1 */
//将rt_thread_switch_interrupt_flag 置1
LDR r1, =rt_thread_switch_interrupt_flag
MOV r0, #1
STR r0, [r1]
/* set the PendSV and SysTick exception priority */
//将systick和pendsv优先级都设置为最低
LDR r0, =NVIC_SYSPRI2
LDR r1, =NVIC_PENDSV_PRI
LDR.W r2, [r0,#0x00] /* read */
ORR r1,r1,r2 /* modify */
STR r1, [r0] /* write-back */
//写28bit 置1将悬起Pendsv中断,如果当前没有其他中断发生,那么将进入pendsv handler
LDR r0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
LDR r1, =NVIC_PENDSVSET
STR r1, [r0]
/* restore MSP */
LDR r0, =SCB_VTOR //获取SCB_VTOR寄存器的地址
LDR r0, [r0] //获取SCB_VTOR寄存器的值,该值保存向量表的地址
LDR r0, [r0] //获取向量表偏移为0的值,即为MSP指针(启动文件中向量表的排布)
NOP
MSR 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, PRIMASK
CPSID I
/* get rt_thread_switch_interrupt_flag */
//判断rt_thread_switch_interrupt_flag,为0则退出pendsv handler
LDR r0, =rt_thread_switch_interrupt_flag
LDR r1, [r0]
CBZ r1, pendsv_exit /* pendsv already handled */
/* clear rt_thread_switch_interrupt_flag to 0 */
//清理rt_thread_switch_interrupt_flag
MOV r1, #0x00
STR r1, [r0]
//判断是否需要保存上文,启动第一个线程的时候不需要保存上文。
LDR r0, =rt_interrupt_from_thread
LDR 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_thread
LDR 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. */
#endif
pendsv_exit:
/* restore interrupt */
MSR PRIMASK, r2
//在进入异常服务程序后,LR的值被自动更新为特殊的EXC_RETURN,这
//是一个高28位全为1的值,只有[3:0]的值有特殊含义
//bit2 == 1 从进程堆栈中做出栈操作,返回后使用PSP
ORR lr, lr, #0x04
BX 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;//线程时间片-1
if (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;
#else
register 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);
#endif
if (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, %function
rt_hw_context_switch_interrupt:
rt_hw_context_switch:
/* set rt_thread_switch_interrupt_flag to 1 */
LDR r2, =rt_thread_switch_interrupt_flag
LDR r3, [r2]
CMP r3, #1
BEQ _reswitch //判断rt_thread_switch_interrupt_flag是否为1,为1说明上一次线程切换没有完成,跳转到_reswitch
MOV r3, #1 //rt_thread_switch_interrupt_flag 为0,将其置1
STR 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] //悬起pendsv
BX 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 > 32
thread->number = thread->current_priority >> 3; /* 5bit */
thread->number_mask = 1 << thread->number;
thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */
#else
thread->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 > 32
thread->number = thread->current_priority >> 3; /* 5bit */
thread->number_mask = 1 << thread->number;
thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */
#else
thread->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_HEAP
else //动态线程使用delete
{
return rt_thread_delete(thread);
}
#endif
default:
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中移除。