Xv6内核分析(七)

gewenbin
gewenbin
gewenbin
188
文章
15
评论
2020年12月20日17:17:41 评论 414

scheduler线程分析

1. scheduler函数

Xv6内核分析(七)

当检索到有一个空闲的PCB后,将PCB的地址记录在c->proc成员中。接着调用switchuvm。

2. switchuvm函数

Xv6内核分析(七)

pushcli和popcli实现如下功能:

  • 如果在调用pushcli之前,中断是关的,则调用popcli后中断还是关的。
  • 如果在调用pushcli之前,中断是开的,则调用pushcli关中断,调popcli之后开中断。

2.1 设置TSS描述符

接着设置了任务段TSS描述符,TSS段描述符内容如下:

Xv6内核分析(七)

TSS段用于恢复一个任务执行的处理器状态信息。TSS段详细内容如下:

Xv6内核分析(七)

从代码中可以看出,每个cpu结构中都有一个TSS段,TSS段中的SS和ESP用来表示一个进程的内核栈地址。

2.2 设置TR寄存器

TR寄存器描述如下:

Xv6内核分析(七)

Xv6内核分析(七)

通过ltr指令加载段选择子到TR寄存器中。

2.3 切换进程页表

最后将CR3寄存器切换到当前进程的页表,switchuvm做的事情总结如下:

  • 设置当前cpu中的GDT表中的TSS段描述符。
  • 设置TSS段中的ss和esp为要运行进程的内核栈地址。
  • 切换CR3寄存器为要运行进程的页目录地址。

3. 进程切换

接着设置进程的状态为RUNNING,然后调用swtch切换到第一个进程initcode中执行。

swtch的原型如下:

void swtch(struct context**, struct context*);

第一个参数用来保存old的context在old栈中的地址,是出参。第二个参数用来表示new的context在new栈中的地址,是入参。

具体实现如下:

Xv6内核分析(七)

首先保存老的上下文在老的栈中,来看看在scheduler线程中swtch的调用:

Xv6内核分析(七)

可以看出,老的上下文就是指scheduler线程的上下文,新的上下文就是指即将要运行的进程的上下文,这个上下文在创建新进程时通过allocproc在新的进程的内核栈中构造好的。swtch的流程如下;

  • 老的上下文保存在老的内核栈中。
  • 切换内核栈指针。
  • 恢复新栈中的上下文。
  • 最后通过ret返回。

注意,如果新进程是第一次运行,那么ret返回到forkret函数中执行。

我们来看看新进程被切换运行的全过程:

Xv6内核分析(七)

当新进程的四个寄存器被弹出栈空间时,栈中的eip指向的是进程之前调用swtch()函数的下一条指令的地址,当调用ret时,ret指令将esp指向的栈中保存的eip值赋值给eip寄存器,然后cpu就从新的eip地址执行指令,也就相当于新进程运行了。

gewenbin
  • 本文由 发表于 2020年12月20日17:17:41
  • 转载请务必保留本文链接:http://www.databusworld.cn/9429.html
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: