Appearance
RT-Thread线程管理(源代码分析01--用户API)
基础知识
在进行任务切换的时候, 会使用中断函数PendSV以及使用系统时钟Systick, 具体的可以看我的这些笔记, 或者Cotex-M3权威指南
Cotex-M3内核寄存器详解(寄存器-栈-中断向量表)-CSDN博客
Cotex-M3中断处理的具体行为(状态保存以及恢复机制等)-CSDN博客
Cotex-M3内核定时器Systick,电源管理,复位以及多处理器机制-CSDN博客
为了保证返回以后可以继续执行, 需要保存当前线程的上下文存在栈中,当线程要恢复运行时,再从栈中读取上下文信息,进行恢复。
全局变量
c
rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX]; //记录各个优先级的任务的链表
rt_uint32_t rt_thread_ready_priority_group; //用一个32位的变量记录优先级
rt_list_t rt_thread_defunct; //记录需要空闲进程释放的进程链表
用户接口分析
创建
c
/**
* 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;
//这一个在对象管理里面分析过了, 主要是获取一个thread大小的内存以及保存对象的信息
thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread,
name);
if (thread == RT_NULL)
return RT_NULL;
//获取一个栈大小的内存
stack_start = (void *)RT_KERNEL_MALLOC(stack_size);
if (stack_start == RT_NULL)
{
/* allocate stack failure */
rt_object_delete((rt_object_t)thread);
return RT_NULL;
}
//实现初始时候的管理结构体的信息, 以及栈的内容
_rt_thread_init(thread,
name,
entry,
parameter,
stack_start,
stack_size,
priority,
tick);
return thread;
}
RTM_EXPORT(rt_thread_create);
c
//初始化一个线程
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));
thread->entry = (void *)entry;
thread->parameter = parameter;
/* stack init */
thread->stack_addr = stack_start;
thread->stack_size = stack_size;
/* init thread stack 把栈里面内存设置为'#' */
rt_memset(thread->stack_addr, '#', thread->stack_size);
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);
/* priority init */
RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
thread->init_priority = priority;
thread->current_priority = priority;
thread->number_mask = 0;
/* 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 初始化一个时钟,未开启 */
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;
}
c
//记录信息以及初始化栈
/**
* This function will initialize thread stack
*
* @param tentry the entry of thread
* @param parameter the parameter of entry
* @param stack_addr the beginning stack address
* @param texit the function will be called when thread exit
*
* @return stack address
*/
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);
stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
stk -= sizeof(struct 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;
}
stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument C语言会使用这一个寄存器传递信息 */
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 */
/* return task's current stack address */
return stk;
}
c//这一个是需要用户自己保存的信息 struct stack_frame { /* r4 ~ r11 register */ rt_uint32_t r4; rt_uint32_t r5; rt_uint32_t r6; rt_uint32_t r7; rt_uint32_t r8; rt_uint32_t r9; rt_uint32_t r10; rt_uint32_t r11; struct exception_stack_frame exception_stack_frame; };
c//这一个是系统自动保存的寄存器信息 struct exception_stack_frame { rt_uint32_t r0; rt_uint32_t r1; rt_uint32_t r2; rt_uint32_t r3; rt_uint32_t r12; rt_uint32_t lr; rt_uint32_t pc; rt_uint32_t psr; };
可以实现这样的一个结果
开启
c
/**
* 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)
{
/* set current priority to initialize priority */
thread->current_priority = thread->init_priority;
/* calculate priority attribute 使用一个32位的变量记录优先级*/
thread->number_mask = 1L << thread->current_priority;
//打印一条信息
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;
/* then resume it 使用这一个开启 */
rt_thread_resume(thread);
if (rt_thread_self() != RT_NULL)
{
/* do a scheduling 当前已经开启调度了 */
rt_schedule();
}
return RT_EOK;
}
RTM_EXPORT(rt_thread_startup);
挂起相关
c
/**挂起一个线程
* 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 stat;
register rt_base_t temp;
//获取这一个线程的状态
stat = thread->stat & RT_THREAD_STAT_MASK;
if ((stat != RT_THREAD_READY) && (stat != RT_THREAD_RUNNING))
{
//这一个线程以及不是运行的线程了
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();
if (stat == RT_THREAD_RUNNING)//这一个线程正在运行
{
/* not suspend running status thread on other core 这是一个多核的处理 */
RT_ASSERT(thread == rt_thread_self());
}
/* change thread stat */
rt_schedule_remove_thread(thread); //从链表里面移除以及更新全局变量
thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK); //更新状态
/* 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;
}
RTM_EXPORT(rt_thread_suspend);
c
/*
* This function will remove a thread from system ready queue.
*
* @param thread the thread to be removed
*
* @note Please do not invoke this function in user application.
*/
void rt_schedule_remove_thread(struct rt_thread *thread)
{
register rt_base_t level;
RT_ASSERT(thread != RT_NULL);
/* disable interrupt */
level = rt_hw_interrupt_disable();
/* remove thread from ready list 把这个任务从对应优先级链表里面移除 */
rt_list_remove(&(thread->tlist));
if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))
{
//这个优先级没有任务了, 更新一下记录
rt_thread_ready_priority_group &= ~thread->number_mask;
}
/* enable interrupt */
rt_hw_interrupt_enable(level);
}
恢复一个线程
c
/**
* 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;
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 这里我没有看到有加入suspend链表的代码 */
rt_list_remove(&(thread->tlist));
rt_timer_stop(&thread->thread_timer);
/* enable interrupt */
rt_hw_interrupt_enable(temp);
/* insert to schedule ready list */
rt_schedule_insert_thread(thread);
RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread));
return RT_EOK;
}
RTM_EXPORT(rt_thread_resume);
c
void rt_schedule_insert_thread(struct rt_thread *thread)
{
register rt_base_t temp;
RT_ASSERT(thread != RT_NULL);
/* disable interrupt */
temp = rt_hw_interrupt_disable();
/* it's current thread, it should be RUNNING thread */
if (thread == rt_current_thread)
{
//这个在操作的线程正在运行, 不需要改变链表, 以防通过自己插入自己, 更新链表起到一直执行的效果
thread->stat = RT_THREAD_RUNNING | (thread->stat & ~RT_THREAD_STAT_MASK);
goto __exit;
}
/* READY thread, insert to ready queue 更新状态*/
thread->stat = RT_THREAD_READY | (thread->stat & ~RT_THREAD_STAT_MASK);
/* insert thread to ready list 插入在运行的链表, 按照线程的优先级, 放在最前面 */
rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
&(thread->tlist));
/* set priority mask 更新全局的最高优先级 */
rt_thread_ready_priority_group |= thread->number_mask;
__exit:
/* enable interrupt */
rt_hw_interrupt_enable(temp);
}
延时
c
/**
* 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;
/* set to current thread 获取当前的进程 */
thread = rt_thread_self();
/* disable interrupt */
temp = rt_hw_interrupt_disable();
/* 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;
}
c
/**任务的超时函数
* 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;
/* 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();
}
c
/**
* This function will let current thread delay for some milliseconds.
*
* @param tick the delay time
*
* @return RT_EOK
*/
rt_err_t rt_thread_mdelay(rt_int32_t ms)
{
rt_tick_t tick;
//时钟转换
tick = rt_tick_from_millisecond(ms);
return rt_thread_sleep(tick);
}