Linux 进程调度
线程状态(context)
程序计数器(Program Counter),它表示当前线程执行指令的位置。
保存变量的寄存器。
程序的Stack。通常来说每个线程都有属于自己的Stack,Stack记录了函数调用的记录,并反映了当前线程的执行点。
xv6的线程切换
从一个用户进程切换到另一个用户进程,都需要从第一个用户进程接入到内核中,保存用户进程的状态并运行第一个用户进程的内核线程。
再从第一个用户进程的内核线程切换到第二个用户进程的内核线程。
之后,第二个用户进程的内核线程暂停自己,并恢复第二个用户进程的用户寄存器。
最后返回到第二个用户进程继续执行
线程切换函数
xv6在这部分设计的非常巧妙,
其使用swtch(&p->context, &mycpu()->context)汇编函数,实现了两个函数sched scheduler的跳转,
达成了进程context以及调度器context的切换
swtch函数(汇编函数)
swtch函数(避开switch关键字)会保存用户进程P1对应内核线程的寄存器至context对象。所以有两类寄存器:用户寄存器存在trapframe中,内核线程的寄存器存在context中。
实际上,swtch函数并不是直接从一个内核线程切换到另一个内核线程。XV6中,一个CPU上运行的内核线程可以直接切换到的是这个CPU对应的调度器线程。所以如果我们运行在CPU0,swtch函数会恢复之前为CPU0的调度器线程保存的寄存器和stack pointer,之后就在调度器线程的context下执行schedulder函数中。
schedulder函数
schedulder函数由调度器线程执行。在schedulder函数中会做一些清理工作,例如将进程P1设置成RUNABLE状态。之后再通过进程表单找到下一个RUNABLE进程。假设找到的下一个进程是P2(虽然也有可能找到的还是P1),schedulder函数会再次调用swtch函数,完成下面步骤:
- 先保存自己的寄存器到调度器线程的context对象
- 找到进程P2之前保存的context,恢复其中的寄存器
- 因为进程P2在进入RUNABLE状态之前,如刚刚介绍的进程P1一样,必然也调用了swtch函数。所以之前的swtch函数会被恢复,并返回到进程P2所在的系统调用或者中断处理程序中(注,因为P2进程之前调用swtch函数必然在系统调用或者中断处理程序中)。
- 不论是系统调用也好中断处理程序也好,在从用户空间进入到内核空间时会保存用户寄存器到trapframe对象。所以当内核程序执行完成之后,trapframe中的用户寄存器会被恢复。
- 最后用户进程P2就恢复运行了。
sched函数
sched函数由用户线程调用,切换到调度器线程。其与schedulder函数互为协程的关系,也将调用swtch函数。根据线程切换机制,sched调用swtch函数后,CPU的下一条指令处于schedulder函数的swtch函数后,原因是swtch函数保存了ra(返回地址)寄存器,因此sched调用swtch函数后,当前ra变成了调度器线程的ra,即上一次调度器线程调用schedulder函数时存储的ra值,故接下来执行schedulder函数swtch调用后的代码。同理,schedulder函数调用swtch函数后,CPU将转移到sched函数。
void
sched(void)
{
int intena;
struct proc *p = myproc();
// 进行一系列判断
if(!holding(&p->lock))
panic("sched p->lock");
if(mycpu()->noff != 1)
panic("sched locks");
if(p->state == RUNNING)
panic("sched running");
if(intr_get())
panic("sched interruptible");
intena = mycpu()->intena;
// 交换上下文环境
swtch(&p->context, &mycpu()->context);
mycpu()->intena = intena;
}
// Per-CPU process scheduler.
// Each CPU calls scheduler() after setting itself up.
// Scheduler never returns. It loops, doing:
// - choose a process to run.
// - swtch to start running that process.
// - eventually that process transfers control
// via swtch back to the scheduler.
//
void
scheduler(void)
{
struct proc *p;
struct cpu *c = mycpu();
c->proc = 0;
for(;;){
// Avoid deadlock by ensuring that devices can interrupt.
intr_on();
for(p = proc; p < &proc[NPROC]; p++) {
acquire(&p->lock);
if(p->state == RUNNABLE) {
// Switch to chosen process. It is the process's job
// to release its lock and then reacquire it
// before jumping back to us.
p->state = RUNNING;
c->proc = p;
// 将当前上下文环境交换到进程上下文环境,将控制权给进程
swtch(&c->context, &p->context);
// Process is done running for now.
// It should have changed its p->state before coming back.
c->proc = 0;
}
release(&p->lock);
}
}
}
# Context switch
#
# void swtch(struct context *old, struct context *new);
#
# Save current registers in old. Load from new.
.globl swtch
swtch:
sd ra, 0(a0)
sd sp, 8(a0)
sd s0, 16(a0)
sd s1, 24(a0)
sd s2, 32(a0)
sd s3, 40(a0)
sd s4, 48(a0)
sd s5, 56(a0)
sd s6, 64(a0)
sd s7, 72(a0)
sd s8, 80(a0)
sd s9, 88(a0)
sd s10, 96(a0)
sd s11, 104(a0)
ld ra, 0(a1)
ld sp, 8(a1)
ld s0, 16(a1)
ld s1, 24(a1)
ld s2, 32(a1)
ld s3, 40(a1)
ld s4, 48(a1)
ld s5, 56(a1)
ld s6, 64(a1)
ld s7, 72(a1)
ld s8, 80(a1)
ld s9, 88(a1)
ld s10, 96(a1)
ld s11, 104(a1)
ret
Linux 进程调度的更多相关文章
- linux进程调度之 FIFO 和 RR 调度策略
转载 http://blog.chinaunix.net/uid-24774106-id-3379478.html linux进程调度之 FIFO 和 RR 调度策略 2012-10-19 18 ...
- Linux进程调度原理
Linux进程调度原理 Linux进程调度机制 Linux进程调度的目标 1.高效性:高效意味着在相同的时间下要完成更多的任务.调度程序会被频繁的执行,所以调度程序要尽可能的高效: 2.加强交互性能: ...
- Linux进程调度原理【转】
转自:http://www.cnblogs.com/zhaoyl/archive/2012/09/04/2671156.html Linux进程调度的目标 1.高效性:高效意味着在相同的时间下要完成更 ...
- Linux进程调度与源码分析(二)——进程生命周期与task_struct进程结构体
1.进程生命周期 Linux操作系统属于多任务操作系统,系统中的每个进程能够分时复用CPU时间片,通过有效的进程调度策略实现多任务并行执行.而进程在被CPU调度运行,等待CPU资源分配以及等待外部事件 ...
- Linux进程调度与源码分析(一)——简介
本系列文章主要是近期针对Linux进程调度源码进行阅读与分析后的经验总结,分析过程中可能结合部分Linux网络编程的相关知识以便于理解,加深对Linux进程调度的理解和知识分享. 本系列文章主要结合L ...
- Linux进程调度(3):进程切换分析
3.调度函数schedule()分析 当kernel/sched.c:sched_tick()执行完,并且时钟中断返回时,就会调用kernel/sched.c:schedule()完成进程切换.我们 ...
- 深度讲解Linux内存管理和Linux进程调度-打通任督二脉
我在多年的工程生涯中发现很多工程师碰到一个共性的问题:Linux工程师很多,甚至有很多有多年工作经验,但是对一些关键概念的理解非常模糊,比如不理解CPU.内存资源等的真正分布,具体的工作机制,这使得他 ...
- [转载]Linux进程调度原理
[转载]Linux进程调度原理 Linux进程调度原理 Linux进程调度的目标 1.高效性:高效意味着在相同的时间下要完成更多的任务.调度程序会被频繁的执行,所以调度程序要尽可能的高效: 2.加强交 ...
- 【原创】(五)Linux进程调度-CFS调度器
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- 【原创】(六)Linux进程调度-实时调度器
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
随机推荐
- 1.Vuejs-第一个实例
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- C++内存管理:new / delete 和 cookie
new 和 delete C++的内存申请和释放是通过 new 和 delete 实现的, 而new 和 delete 其实就是通过 malloc 和 free 实现的. new 申请内存分为三个步骤 ...
- 【划重点】Python matplotlib绘图建立画布和坐标系
一.建立画布 import matplotlib.pyplot as plt import numpy as np x=np.arange(8) y=np.arange(8) print(x,y) # ...
- hooks中,useState异步问题解决方案
问题描述: 在hooks中,修改状态的是通过useState返回的修改函数实现的.它的功能类似于class组件中的this.setState().而且,这两种方式都是异步的.可是this.setSta ...
- *CTF pwn write up
第一次做出XCTF的题目来,感谢wjh师傅的指点,虽然只做出一道最简单的pwn题,但是还是挺开心的.此贴用来记录一下,赛后试着看看其他大师傅的wp,看看能不能再做出一道题来. babyheap 程序有 ...
- CF749B Parallelogram is Back 题解
Content 给出平行四边形的三个顶点 \((x_1,y_1),(x_2,y_2),(x_3,y_3)\),求出所有可能的第四个顶点. 数据范围:\(\forall i\in[1,3],-1000\ ...
- Spring学习(四)在Web项目中实例化IOC容器
1.前言 前面我们讲到Spring在普通JAVA项目中的一些使用.本文将介绍在普通的Web项目中如何实例化Spring IOC容器.按照一般的思路.如果在Web中实例化Ioc容器.这不得获取Conte ...
- JAVA将Object数组转换为String数组
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String; java将Object[ ...
- summernote富文本图片上传,增加视频上传功能、批量上传方法
Summernote 是一个简单灵活的所见即所得的 HTML 在线编辑器,基于 jQuery 和 Bootstrap 构建,支持快捷键操作,提供大量可定制的选项. 但是却只有图片上传功能,没有视频上传 ...
- VS2015 up3激活key
密钥 专业版:HMGNV-WCYXV-X7G9W-YCX63-B98R2 企业版:HM6NR-QXX7C-DFW2Y-8B82K-WTYJV