2020-2021-1 20209309闫兆森 《Linux内核原理与分析》第三周作业

实验过程

make

粘贴代码

修改代码

make通过

运行

代码分析

  1. 启动进程0的关键代码:
asm volatile(
    "movl %1,%%esp
	" 	/* set task[pid].thread.sp to rsp */
    "pushl %1
	" 	        /* push rbp */
    "pushl %0
	" 	        /* push task[pid].thread.ip */
    "ret
	" 	            /* pop task[pid].thread.ip to rip */
    : 
    : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)
);

由于这里是单线程的进程所以在调度的时候,实际是对单个线程环境维护(线程是调度的基本单位),也就是一个栈空间的sp与一个代码段的ip,在启动的时候该线程的栈空间是空的,所以对应之前的栈顶就是对应的栈底,并且栈顶等于栈底,而要想让其运行则需要将ip寄存器修改为对应线程的thread.ip,这里使用的是ret的方式,先将ip入栈之后ret设置。

  1. 进程调度的关键代码
asm volatile(	
    "pushl %%ebp
	"       /* save rbp of prev */
    "movl %%esp,%0
	"     /* save rsp of prev */
    "movl %2,%%esp
	"     /* restore  rsp of next */
    "movl $1f,%1
	"       /* save rip of prev */	
    "pushl %3
	" 
    "ret
	" 	            /* restore  rip of next */
    "1:	"                  /* next process start here */
    "popl %%ebp
	"
    : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
    : "m" (next->thread.sp),"m" (next->thread.ip)
); 

虽然是进程调度,但是实际处理的还是线程,将正在运行的线程数据保存,包括对栈底的保存(直接入栈),对栈顶的保存(存入对应的结构体),对ip的保存,这里区分了线程运行的状态,每一个运行过的线程都给了一个统一的标号点1,之后就是新运行线程环境的设置,对应设置其栈顶,使用ret的方式设置其ip位置,栈为空栈底等于栈底,并且这里每个线程都独享一个字符数组作为栈,每个栈底ebp对应在数组中的偏置位置是相同的。

  1. 小结

这里虽然模拟了单线程进程的调度,实际在多线程进程中的调度也大致相同,都是对线程运行的环境进行一个维护,相同进程的线程之间的调度可以在同一个进程控制块内进行调整,不同进程之间的线程调度则需要进行跨进程的调度,需要去维护多个进程控制块的信息,同进程线程共享进程资源,所以其与不同进程的线程的调度相比而言要复杂一些,但是其大致的流程也都类似。

原文地址:https://www.cnblogs.com/yanzs/p/13873844.html