操作系统真象还原第九章-部分难点总结与浅分析(一)

一、关于为什么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; //中断号
    uint32_t edi;
    uint32_t esi;
    uint32_t ebp;
    uint32_t esp_dummy;
    uint32_t ebx;
    uint32_t edx;
    uint32_t ecx;
    uint32_t eax;
    uint32_t gs;
    uint32_t fs;
    uint32_t es;
    uint32_t ds;
    
    uint32_t err_code;
    void (*eip) (void);        //这里声明了一个函数指针 
    uint32_t cs;
    uint32_t eflags;
    void* esp;
    uint32_t ss;

thread线程栈结构

uint32_t ebp;
    uint32_t ebx;
    uint32_t edi;
    uint32_t esi;

    void(*eip)(thread_func* func,void* func_arg);
    void (*unused_retaddr);
    thread_func* function;
    void* func_arg;

.........

pcb(intr_struct-4096)

uint32_t* self_kstack;
    enum task_status status;
    uint8_t priority;
    char name[16];
    uint8_t ticks;
    uint32_t elapsed_ticks;
    struct list_elem general_tag;
    struct list_elem all_list_tag;
    uint32_t* pgdir;
    struct virtual_addr userprog_vaddr;
    uint32_t stack_magic;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值