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版本: ...
随机推荐
- SVN终端演练-版本回退
1. 版本回退概念以及原因? 概念: 是指将代码(本地代码或者服务器代码), 回退到之前记录的某一特定版本 原因: 如果代码做错了, 想返回之前某个状态重做;2. 修改了,但未提交的情况下 ...
- 【Xcode】sh: pause: command not found
system("pause"); 只适合于DOS和Windows系统,不适合Linux系统. 直接删掉就可以. 或者改为: #include <unistd.h> pa ...
- 【Office】【Excel】将多个工作表合为一个工作表
在工作表中按下alt+F11打开vba编辑窗口,在菜单栏中选择[插入]=>[模板],将下面的代码粘贴过去,然后运行即可 点击查看代码 Sub 合并当前工作簿下的所有工作表() On Error ...
- JavaOOP对象和封装
对象: 前言: 在程序员眼中,世界万物皆为对象.世界上有两种人,一种是懂二进制的人,一种就是不懂二进制的人. 面向对象设计的过程就是抽象的过程. 步骤: 第一步:发现类 第二步:发现类的属性 第三步: ...
- SOUI3界面编辑器使用说明
SOUI一直没有官方的界面编辑器,关键是我自己一直坚持手写界面更好控制. 大概是2年前,网友"指尖"开发了一个SOUI2的编辑器,功能非常多,特点是可以拖动控件来实现可视化布局. ...
- Set数据结构基本介绍
构造 const set = new Set([1, 2, 3, 4, 4]); 可接受的参数为所有具有iterable 接口的数据 特性: 类似数组,无重复值. const set = new Se ...
- mit6.830 - lab1 - 存储模型 - 题解
1.Intro github : https://github.com/CreatorsStack/CreatorDB lab1实现数据库基本的存储逻辑结构,具体包括:Tuple,TupleDesc, ...
- windows10 安装 Mysql8.0
目录 1.Mysql8.0下载 2.配置环境变量 3.在安装目录下创建my.ini文件 4 初始化Mysql 5 安装至系统服务 6 更改密码 1.Mysql8.0下载 2.配置环境变量 将下载后文件 ...
- CF938A Word Correction 题解
Content 有一个长度为 \(n\) 的,只包含小写字母的字符串,只要有两个元音字母相邻,就得删除后一个元音字母(\(\texttt{a,e,i,o,u,y}\) 中的一个),请求出最后得到的字符 ...
- linux安装软件系列之yum安装
自动搜索最快镜像插件: yum install yum-fastestmirror 安装yum图形窗口插件: yum install yumex 1.安装 yum install 全部安装 yum i ...