FROM:https://blog.csdn.net/xichangbao/article/details/51484585
从thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));展开对lk中thread的分析。
struct thread。
typedef struct thread {
int magic; // thread魔数'thrd'
struct list_node thread_list_node; // thread链表,用于将lk中的thread链接起来
/* active bits */
struct list_node queue_node; // 运行队列链表
int priority; // thread优先级
enum thread_state state; // thread状态,分为THREAD_SUSPENDED,THREAD_READY, THREAD_RUNNING, THREAD_BLOCKED, THREAD_SLEEPING, THREAD_DEATH等六种状态
int saved_critical_section_count; // 相当于一个简单的锁机制
int remaining_quantum; //
/* if blocked, a pointer to the wait queue */
struct wait_queue *blocking_wait_queue; // 等待队列
status_t wait_queue_block_ret; // 等待队列唤醒时的状态
/* architecture stuff */
struct arch_thread arch; // 比较重要,目前只保留的thread的sp(堆栈)指针
/* stack stuff */
void *stack; // 初始化时分配的堆栈空间指针
size_t stack_size; // 初始化时分配的堆栈空间大小
/* entry point */
thread_start_routine entry; // thread入口函数
void *arg; // thread入口函数的参数
/* return code */
int retcode; // thread退出时的返回值
/* thread local storage */
uint32_t tls[MAX_TLS_ENTRY]; // 线程本地存储,未实现
char name[32]; // 线程名称
} thread_t;
thread_create()。
thread_t *thread_create(const char *name, thread_start_routine entry, void *arg, int priority, size_t stack_size)
{
thread_t *t;
t = malloc(sizeof(thread_t)); // 从lk的heap中分配thread结构体内存,lk的heap实现比较简单,但功能齐全,有时间可以看一下
if (!t)
return NULL;
init_thread_struct(t, name); // 初始化thread,做了三个动作,结构体清零,设置魔数,设置name
t->entry = entry; // 对thread入口函数指针进行赋值
t->arg = arg; // 对thread入口函数参数进行赋值
t->priority = priority; // 设置thread优先级
t->saved_critical_section_count = 1; /* we always start inside a critical section */
t->state = THREAD_SUSPENDED; // 设置thread的当前状态为挂起
t->blocking_wait_queue = NULL; // 等待队列为空
t->wait_queue_block_ret = NO_ERROR;
/* create the stack */
t->stack = malloc(stack_size); // 为thread分配堆栈
if (!t->stack) {
free(t);
return NULL;
}
t->stack_size = stack_size; // 记录堆栈大小
/* inheirit thread local storage from the parent */
int i;
for (i=0; i < MAX_TLS_ENTRY; i++)
t->tls[i] = current_thread->tls[i]; // 未实现
/* set up the initial stack frame */
arch_thread_initialize(t); // 设置栈帧等,这个函数十分关键,因为涉及到了thread的切换
/* add it to the global thread list */
enter_critical_section();
list_add_head(&thread_list, &t->thread_list_node); // 将新生成的thread加入到lk的thread链表中
exit_critical_section();
return t;
}
struct context_switch_frame {
vaddr_t r4;
vaddr_t r5;
vaddr_t r6;
vaddr_t r7;
vaddr_t r8;
vaddr_t r9;
vaddr_t r10;
vaddr_t r11;
vaddr_t lr;
vaddr_t usp;
vaddr_t ulr;
};
void arch_thread_initialize(thread_t *t)
{
// create a default stack frame on the stack
vaddr_t stack_top = (vaddr_t)t->stack + t->stack_size; // 计算栈顶地址
// make sure the top of the stack is 8 byte aligned for EABI compliance
stack_top = ROUNDDOWN(stack_top, 8); // 向下8byte对齐
struct context_switch_frame *frame = (struct context_switch_frame *)(stack_top);
frame--; // 这两行代码实现了的在栈顶预留了一个context_switch_frame结构体的内存
// fill it in
memset(frame, 0, sizeof(*frame)); // 对context_switch_frame结构体清零
frame->lr = (vaddr_t)&initial_thread_func; // 栈帧的lr指针指向initial_thread_func函数的地址
// set the stack pointer
t->arch.sp = (vaddr_t)frame; // 由于我们已经是使用了堆栈中的一部分(context_switch_frame 结构体使用的和向下对齐造成的),所以需要更新堆栈指针
}
static void initial_thread_func(void)
{
int ret;
// dprintf("initial_thread_func: thread %p calling %p with arg %p\n", current_thread, current_thread->entry, current_thread->arg);
// dump_thread(current_thread);
/* exit the implicit critical section we're within */
exit_critical_section();
ret = current_thread->entry(current_thread->arg); // 调用当前thread的entry函数,对bootstrap2来说就bootstrap2()函数
// dprintf("initial_thread_func: thread %p exiting with %d\n", current_thread, ret);
thread_exit(ret); // thread退出时做一些处理
}
void thread_exit(int retcode)
{
#if THREAD_CHECKS
ASSERT(current_thread->magic == THREAD_MAGIC);
ASSERT(current_thread->state == THREAD_RUNNING);
#endif
// dprintf("thread_exit: current %p\n", current_thread);
enter_critical_section();
/* enter the dead state */
current_thread->state = THREAD_DEATH; // 设置thread状态为死亡
current_thread->retcode = retcode; // 设置thread的退出值
/* schedule a dpc to clean ourselves up */
dpc_queue(thread_cleanup_dpc, (void *)current_thread, DPC_FLAG_NORESCHED); // 对当前thread进行清理动作
/* reschedule */
thread_resched(); // thread调度,从lk thread链表中选一个thread继续运行
panic("somehow fell through thread_exit()\n"); // 正常情况代码永远不会执行到这里。
for(;;);
}
static void thread_cleanup_dpc(void *thread)
{
thread_t *t = (thread_t *)thread;
// dprintf(SPEW, "thread_cleanup_dpc: thread %p (%s)\n", t, t->name);
#if THREAD_CHECKS
ASSERT(t->state == THREAD_DEATH);
ASSERT(t->blocking_wait_queue == NULL);
ASSERT(!list_in_list(&t->queue_node));
#endif
/* remove it from the master thread list */
enter_critical_section();
list_delete(&t->thread_list_node); // 从lk thread链表中删除对应的thread
exit_critical_section();
/* free its stack and the thread structure itself */
if (t->stack)
free(t->stack); // 释放堆栈内存资源。
free(t); // 释放thread结构体自身占用的内存资源
}
thread_resume()。
status_t thread_resume(thread_t *t)
{
#if THREAD_CHECKS
ASSERT(t->magic == THREAD_MAGIC);
ASSERT(t->state != THREAD_DEATH);
#endif
if (t->state == THREAD_READY || t->state == THREAD_RUNNING) // 仅当thread为挂起状态才会进行唤醒
return ERR_NOT_SUSPENDED;
enter_critical_section();
t->state = THREAD_READY; // 设置thread状态为就绪
insert_in_run_queue_head(t); // 将thread插入运行队列的头部
thread_yield(); // 让渡处cpu资源,执行新的thread
exit_critical_section();
return NO_ERROR;
}
void thread_yield(void)
{
#if THREAD_CHECKS
ASSERT(current_thread->magic == THREAD_MAGIC);
ASSERT(current_thread->state == THREAD_RUNNING);
#endif
enter_critical_section();
#if THREAD_STATS
thread_stats.yields++;
#endif
/* we are yielding the cpu, so stick ourselves into the tail of the run queue and reschedule */
current_thread->state = THREAD_READY; // 将当前thread状态设置为就绪
current_thread->remaining_quantum = 0; //
insert_in_run_queue_tail(current_thread); // 插入到运行队列尾部
thread_resched(); // 执行thread调度
exit_critical_section();
}
void thread_resched(void)
{
thread_t *oldthread;
thread_t *newthread;
// dprintf("thread_resched: current %p: ", current_thread);
// dump_thread(current_thread);
#if THREAD_CHECKS
ASSERT(in_critical_section());
#endif
#if THREAD_STATS
thread_stats.reschedules++;
#endif
oldthread = current_thread; // 保存当前的thread的指针
// at the moment, can't deal with more than 32 priority levels
ASSERT(NUM_PRIORITIES <= 32);
// should at least find the idle thread
#if THREAD_CHECKS
ASSERT(run_queue_bitmap != 0);
#endif
int next_queue = HIGHEST_PRIORITY - __builtin_clz(run_queue_bitmap) - (32 - NUM_PRIORITIES); // 根据优先级选取运行队列
//dprintf(ALWAYS, "bitmap 0x%x, next %d\n", run_queue_bitmap, next_queue);
newthread = list_remove_head_type(&run_queue[next_queue], thread_t, queue_node); // 从运行队列头部选取一个新的thread
#if THREAD_CHECKS
ASSERT(newthread);
#endif
if (list_is_empty(&run_queue[next_queue]))
run_queue_bitmap &= ~(1<<next_queue); // 当选取的运行队列中thread 链表为空时,清除对应优先级的run_queue_bitmap位
#if 0
// XXX make this more efficient
newthread = NULL;
for (i=HIGHEST_PRIORITY; i >= LOWEST_PRIORITY; i--) {
newthread = list_remove_head_type(&run_queue[i], thread_t, queue_node);
if (newthread)
break;
}
#endif
//dprintf(ALWAYS, "newthread: ");
//dump_thread(newthread);
newthread->state = THREAD_RUNNING; // 设置新thread状态为正在运行
if (newthread == oldthread)
return; // 新旧thread相等时,说明没有别的thread了,直接退出thread调度,继续执行
/* set up quantum for the new thread if it was consumed */
if (newthread->remaining_quantum <= 0) {
newthread->remaining_quantum = 5; // XXX make this smarter //
}
#if THREAD_STATS
thread_stats.context_switches++;
if (oldthread == idle_thread) {
bigtime_t now = current_time_hires();
thread_stats.idle_time += now - thread_stats.last_idle_timestamp;
}
if (newthread == idle_thread) {
thread_stats.last_idle_timestamp = current_time_hires();
}
#endif
#if THREAD_CHECKS
ASSERT(critical_section_count > 0);
ASSERT(newthread->saved_critical_section_count > 0);
#endif
#if PLATFORM_HAS_DYNAMIC_TIMER
/* if we're switching from idle to a real thread, set up a periodic
* timer to run our preemption tick.
*/
if (oldthread == idle_thread) {
timer_set_periodic(&preempt_timer, 10, (timer_callback)thread_timer_tick, NULL);
} else if (newthread == idle_thread) {
timer_cancel(&preempt_timer);
}
#endif
/* do the switch */
oldthread->saved_critical_section_count = critical_section_count;
current_thread = newthread; // 将新thread设置当前thread
critical_section_count = newthread->saved_critical_section_count;
arch_context_switch(oldthread, newthread); // 完成thread上下文切换,最终执行新thread的入口函数
}
void arch_context_switch(thread_t *oldthread, thread_t *newthread)
{
// dprintf("arch_context_switch: old %p (%s), new %p (%s)\n", oldthread, oldthread->name, newthread, newthread->name);
arm_context_switch(&oldthread->arch.sp, newthread->arch.sp); // 调用汇编代码,r0为旧thread的arch.sp 的地址,r1为新thread的arch.sp
}
// 这一块对我来说还是只能理解大概,不能透彻的理解的
FUNCTION(arm_context_switch)
/* save all the usual registers + user regs */
/* the spsr is saved and restored in the iframe by exceptions.S */
sub r3, sp, #(11*4) /* can't use sp in user mode stm */ // 这里的sp是r3保存的是sp-11*4的内存地址,即预留了可以保存11个32位寄存器内存空间
mov r12, lr // 将内核lr寄存器值保存到r12寄存器中
stmia r3, { r4-r11, r12, r13, r14 }^ // 保存r4-r11, r12, r13, r14等11个寄存器值(其中r13和r14为用户模式的)到r3指向的内存地址中去
/* save old sp */
str r3, [r0] // 将r3的值(保存了11个寄存器后的堆栈指针)保存到旧thread的的arch.sp中
/* clear any exlusive locks that the old thread holds */
#if ARM_ISA_ARMV7
clrex
#elif ARM_ISA_ARMV6
/* have to do a fake strex to clear it */
ldr r0, =strex_spot
strex r3, r2, [r0]
#endif
/* load new regs */
ldmia r1, { r4-r11, r12, r13, r14 }^ // 从新thread的堆栈中加载r4-r11, r12, r13, r14等11个寄存器的值
mov lr, r12 /* restore lr */ // 从r12中恢复lr的值
add sp, r1, #(11*4) /* restore sp */ // 恢复sp的值
bx lr // 跳到lr处继续执行,由前面的分析可知是跳转到initial_thread_func函数继续执行
总结一下,thread切换的过程,先切换current_thread的指针内容,使其指向新的thread,进行thread切换时,保存旧thread的context_switch_frame的地址到旧thread的arch.sp中,同时从新thread的arch.sp读取context_switch_frame中的信息到相应寄存器中,然后跳转的新thread的lr指向的代码地址继续运行,如果新thread是第一次运行那么它的lr应该指向initial_thread_func,最后在initial_thread_func函数执行current_thread->entry(current_thread->arg)执行新thread的入口函数。
---------------------
作者:xichangbao
来源:CSDN
原文:https://blog.csdn.net/xichangbao/article/details/51484585
版权声明:本文为博主原创文章,转载请附上博文链接!