《操作系统真象还原》第十一篇:实现多线程调度

第十一篇:实现多线程调度

线程调度分为三个步骤

  • 时钟中断处理函数
  • 调度器schedule
  • 任务切换函数switch_to

注册时钟中断处理函数

时间中断处理函数的作用是判断当前进程是否还有时间片,如果没有则进行调度。

void intr_timer_handler(void) {
	struct task_struct* cur_thread = running_thread();
	
	//检查栈是否溢出
	ASSERT(cur_thread->stack_magic == 0x20030621);
	
	//当前进程总时间数+1
	cur_thread->elapsed_ticks++;
	//总的时钟中断数+1
	ticks++;
	
	//时间片用完了则调度新的进程
	if (cur_thread->ticks == 0) {
		schedule();
	} else {
		cur_thread->ticks--;
	}
}

实现调度器

调度器负责找到当前进程的pcb和下一个待运行进程的pcb,并调用任务切换函数实现线程的切换。

//实现任务调度
void schedule(void) {
	ASSERT(get_intr_status() == INTR_OFF);
	
	struct task_struct* cur = running_thread();
	if (cur->status == TASK_RUNNING) {
		//将当前线程加入队列
		ASSERT(!node_find(&thread_ready_list, &cur->general_tag));
		list_append(&thread_ready_list, &cur->general_tag);
		cur->ticks = cur->priority;
		cur->status = TASK_READY;
	} else {
		//若当前线程需要某事发生后才能继续上cpu运行,那么不需要加入就绪队列
	}
	
	//获取下一个待运行的线程,并切换到cpu上
	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);
}

实现任务切换函数

任务切换函数的功能是保持当前进程的上下文,并恢复下一个进程的上下文。并修改eip,实现控制流的转移。

[bits 32]
section .text 
global switch_to
switch_to:
	;栈中此处是返回地址
	push esi
	push edi
	push ebx
	push ebp
	
	
	;得到cur的地址
	mov eax, [esp + 20]
	;保存cur的栈指针
	;pcb的偏移0处是self_kstack
	mov [eax], esp
	
	;以上是保存cur的环境,接下来恢复next的环境
	
	;得到next的地址
	mov eax, [esp + 24]
	;恢复栈指针
	mov esp, [eax]
	
	;恢复寄存器
	pop ebp
	pop ebx
	pop edi
	pop esi
	ret