一、关于为什么runningthread可以正确返回pcb地址的浅析
众所周知,在程序中因为esp经常变换,而跳到另一个函数的esp变化是很难确定的,故第九章中thread函数怎么判定runningthread()是否正确返回pcb的正确地址呢?,下面笔者就这个疑惑对running函数浅析一下。与其说分析running函数,倒不如说是在分析其中的esp是怎么变化的
1.running_thread()函数;此函数返回pcb地址,因为runningthread是通过esp&fffff000返回,要切换线程就要切换esp,即switch_to中:esp放的是next->thread的线程栈地址,因此不同线程栈之间的esp是不同的,
总结一下步骤
1.全局变量task_struct* thread_a与task_struct* thread_b(线程)通过thread_start与thread_init函数初始化(bitmap从内存池中给不同的线程栈分配内存地址)pcb位置在栈底,然后在栈顶给intr_stack与thread_stack预留空间,最终通过switch_to函数切换esp(esp值为thread_stack的地址),
struct task_struct* thread_start(char* name,int prio,thread_func function,void* func_arg){
struct task_struct* thread = get_kernel_pages(1);
init_thread(thread,name,prio);
//init_thread(thread,name,prio);
thread_create(thread,function,func_arg);
ASSERT(!elem_find(&thread_ready_list,&thread->general_tag));
list_append(&thread_ready_list,&thread->general_tag);
/*
asm volatile("movl %0,%%esp;pop %%ebp;pop %%ebx;pop %%edi;pop %%esi;ret"::"g" (thread->self_kstack) : "memory");*/
return thread;
}
即全局变量task_struct* thread_a与task_struct* thread_b(线程)
2.main:init_all()->thread_start()(给两个线程加入链表中)->intr_enable->时钟中断,再经过中断处理函数,此时的running_thread是生效的。无论是第一次执行还是第二次执行线程,此段函数的esp虽然不同但相差不大,cur是pcb的地址,第一次放thread_stack栈地址,第二次调度线程时cur放的上一次的esp值(push ebp后),
3因为schedule()会切换esp,故runningthread也会随之改变,而第二次调度线程切换的esp是回到第一次schedule()后,runningthread()的判定又在switch_to前,不会造成栈混乱。
static void intr_timer_handler(void){
struct task_struct* cur_thread = running_thread();
ASSERT(cur_thread->stack_magic==0x19870916);
cur_thread->elapsed_ticks++;
ticks++;
if(cur_thread->ticks==0){
schedule();
}else{
cur_thread->ticks--;
}
}
void timer_init(){
put_str("timer_init start\n");
//frequency_set(CONTRER0_PORT,COUNTER0_NO,READ_WAITE_LATCH,READ_WAITE_LATCH,COUNTER_MODE,COUNTEER0_VALUE);
register_handler(0x20,intr_timer_handler);
put_str("timer_init_done\n");
}
void schedule(){
ASSERT(intr_get_status()==INTR_OFF);
struct task_struct* cur = running_thread();
if(cur->status == TASK_RUNNING){
ASSERT(!elem_find(&thread_ready_list,&cur->general_tag));
list_append(&thread_ready_list,&cur->general_tag);
cur->ticks = cur->priority;
cur->status = TASK_READY;
}else{
}
ASSERT(!list_empty(&thread_ready_list));
thread_tag = NULL;
thread_tag = list_pop(&thread_ready_list);
struct task_struct* next = elem2entry(struct task_struct,general_tag,thread_tag);
next->status = TASK_RUNNING;
switch_to(cur,next);
}
switch_to:
push esi;
push edi;
push ebx;
push ebp;
mov eax,[esp+20];
mov [eax],esp;
mov eax,[esp+24]
mov esp,[eax];
pop ebp;
pop ebx;
pop edi;
pop esi;
ret
next |
cur |
返回地址 |
中断intr_Struct结构 uint32_t vec_no; //中断号 |
thread线程栈结构 uint32_t ebp; void(*eip)(thread_func* func,void* func_arg); |
......... pcb(intr_struct-4096) uint32_t* self_kstack; |