博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
xv6进程切换-swtch函数
阅读量:5035 次
发布时间:2019-06-12

本文共 3178 字,大约阅读时间需要 10 分钟。

xv6进程切换-swtch函数

进程切换中由于需要保存当前进程的寄存器状态信息,又要将新进程记录的寄存器状态信息加载到寄存器,因此涉及到许多栈的操作,堆栈间的来回切换,容易让人眼花缭乱,难以理解。本文试图分析以下xv6中的进程切换过程。

当前进程通过调用yield函数,进行进程切换。yield函数调用sched函数,sched函数启动swtch函数完成进程切换。整个流程是这样的:

yield->sched->swtch
  • 1

在sched函数中,可以看到,当前进程总是先切换到当前cpu的scheduler切换器:

//void sched(void)swtch(&proc->context, cpu->scheduler);
  • 1
  • 2

切换器是一个死循环,该循环不断在进程表中扫描,选择一个RUNNABLE的进程调度,即从scheduler切换器转换到新选择的进程:

//scheduler切换器voidscheduler(void){  struct proc *p;  for(;;){    // Enable interrupts on this processor. sti(); // Loop over process table looking for process to run. acquire(&ptable.lock); for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ if(p->state != RUNNABLE) continue; // Switch to chosen process. It is the process's job // to release ptable.lock and then reacquire it // before jumping back to us. proc = p; switchuvm(p); p->state = RUNNING; swtch(&cpu->scheduler, proc->context); switchkvm(); // Process is done running for now. // It should have changed its p->state before coming back. proc = 0; } release(&ptable.lock); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

显然,swtch函数是重点。swtch函数的原型是:

void swtch(struct context **old, struct context *new);
  • 1

它的工作主要包括:1. 保存当前(old)进程的上下文。 2. 加载新进程(new)的上下文到机器寄存器中。

contex中其实就是几个寄存器变量,用来保存这些寄存器的值。

swtch的函数代码如下:

# Context switch##   void swtch(struct context **old, struct context *new); # # Save current register context in old # and then load register context from new. .globl swtch swtch: movl 4(%esp), %eax movl 8(%esp), %edx # Save old callee-save registers pushl %ebp pushl %ebx pushl %esi pushl %edi # Switch stacks movl %esp, (%eax) movl %edx, %esp # Load new callee-save registers popl %edi popl %esi popl %ebx popl %ebp ret
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

下面分析以下swtch函数的执行过程。


swtch函数的执行过程

当任意进程调用swtch函数时,该进程的堆栈是下面这个样子的:

这里写图片描述

其中栈中每个存储区域都是4个字节。这里需要提一下,在执行指令call时,当前指令的下一条指令的地址将会push到栈中,也就是上面看到的eip,这样就可以保证在函数返回时,可以回到函数调用的下一条指令的地方。然后swtch开始执行,

movl 4(%esp), %eaxmovl 8(%esp), %edx
  • 1
  • 2

所以寄存器eax和edx都会指向如下图所示的位置:

这里写图片描述
接下来会依次将有关上下文信息的寄存器push到栈中
pushl %ebp  pushl %ebx  pushl %esi  pushl %edi
  • 1
  • 2
  • 3
  • 4

push完之后,就可以堆栈布局就变成下图所示:

这里写图片描述

对比contex和当前的栈布局,可以直观看到,此时在栈上存储的刚好是一个contex。当前的栈顶esp刚好指向当前进程的contex中的第一个元素的地址,所以这里可以说contex中包括了栈信息和寄存器信息,不仅可以用它来进行栈切换,还可以通过它恢复寄存器。因此可以想到,下次重新调度这个进程时,只需要直接将栈上的信息弹到相应寄存器中就可以了。而这个栈顶指针,我们可以直接用proc->contex指针记录就可以了。即

proc->contex = esp;
  • 1

我们继续看swtch函数:

# Switch stacks  movl %esp, (%eax)  movl %edx, %esp
  • 1
  • 2
  • 3

根据注释也可以看到,这两行主要是用于栈的切换。前面我们知道,eax中存储的是指向old_proc->contex的指针,old_proc->contex是指向当前进程的contex的指针,所以movl %esp, (%eax),相当于:

old_proc->contex = esp;
  • 1

也就是让当前进程的contex指针指向栈顶。根据前面的示意图我们可以理解原理。

到此为止,旧进程的contex保存工作已经完成了。

下面的工作自然是怎么把新进程的contex弹出到对应的寄存器中。其实保存过程和弹出恢复过程是对称的

从保存过程中,我们知道新进程的contex信息总是可以通过new_proc->contex获得,因为new_proc->contex指向了new_proc内核栈的栈顶,而栈顶依次保存着上下文寄存器信息所以将new_proc->contex赋值到esp就完成了堆栈切换,再依次pop就可以恢复上下文寄存器信息。但是我们怎么获得new_proc的contex呢?回到前面,我们看到,就进程在调用swtch时,就把new_proc的contex放在了堆栈中,并且根据前面edx=new_proc->contex。所以堆栈切换就是把

esp= edx;
  • 1

然后

popl %edipopl %esipopl %ebxpopl %ebp
  • 1
  • 2
  • 3
  • 4

就可以依次将new_contex中保存的寄存器值依次弹回到对应寄存器中了。

最后的

ret
  • 1

指令将eip弹回。所以新进程会从它上次调用swtch函数的下一条指令开始执行。

转载于:https://www.cnblogs.com/itzxy/p/9293677.html

你可能感兴趣的文章
南海区行政审批管理系统接口规范v0.3(规划)4.2.【queryExpireList】当天到期业务查询...
查看>>
[置顶] 细说Cookies
查看>>
[wp7软件]wp7~~新闻资讯,阅读软件下载大全! 集合贴~~~
查看>>
生成指定位数随机数的方法
查看>>
java的垃圾回收
查看>>
Essential C++学习笔记
查看>>
python+selenium进行简单验证码获取
查看>>
where,having与 group by连用的区别
查看>>
【MySQL】MySQL锁和隔离级别浅析二 之 INSERT
查看>>
Oracle T4-2 使用ILOM CLI升级Firmware
查看>>
4.14上午
查看>>
数据分析 -- 白话一下什么是决策树模型(转载)
查看>>
Java SPI机制原理和使用场景
查看>>
web前端java script学习2017.7.18
查看>>
删除TXPlatform
查看>>
LaTex:图片排版
查看>>
并发访问超时的问题可能性(引用)
查看>>
中小团队基于Docker的Devops实践
查看>>
利用python打开摄像头并保存
查看>>
System函数的使用说明
查看>>