Operating Systems Three Easy Piece
绪论: 为什么需要操作系统
操作系统做的事情大概可以分为三个部分
- 对资源
- 处理并发问题
- 提供持久化的文件系统
OSTEP
设计目标
- 提供抽象方法
- 降低抽象的额外开销
- 提供应用程序的保护
最开始的操作系统只是一系列对硬件操作的
想到看一些早期的数据库实现的论文
进程
进程就是一个运行中的程序
- 将程序代码和静态数据
从磁盘中加载到内存中) 因为虚拟内存机制。 加载可以是, 立刻将程序全部加载到内存中, 也可以是, 只加载目前用到的部分, 。 - 为程序分配堆栈空间
。 - 做一些初始化工作
主要是, 例如, 。 - 跳转到
执行代码, 。
操作系统将这样的一个运行中的程序的概念
对应的
- 地址空间
。 - 寄存器
特殊的寄存器有。 Program Counter: Stack Pointer, 。 - IO
如, 。
操作系统可以对进程做一些操作
- 创建
- 销毁
- 等待
等待一个进程结束。 。 - 获取进程状态
。 - 一些杂项控制
。
当需要同时运行多个进程时
简单的说
- 运行
进程执行中。 。 - 准备就绪
进程可以被调度。 但尚未被调度, 。 - 阻塞
BLOCKING( ) 进程被某些操作阻塞。 无法被调度, 例如。 执行某些, 且, 。
这三种状态可以相互流转
至于怎么流转
xv6
// the registers xv6 will save and restore
// to stop and subsequently restart a process
struct context
{
int eip;
int esp;
int ebx;
int ecx;
int edx;
int esi;
int edi;
int ebp;
};
// the different states a process can be in
enum proc_state
{ UNUSED,
EMBRYO,
SLEEPING,
RUNNABLE,
RUNNING,
ZOMBIE
};
// the information xv6 tracks about each process
// including its register context and state
struct proc
{
char* mem; // Start of process memory
uint sz; // Size of process memory
char* kstack; // Bottom of kernel stack
// for this process
enum proc_state state; // Process state
int pid; // Process ID
struct proc* parent; // Parent process
void* chan; // If !zero, sleeping on chan
int killed; // If !zero, has been killed
struct file* ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
struct context context; // Switch here to run process
struct trapframe* tf; // Trap frame for the
// current interrupt
};
API
Unix
- fork, 将目前的
创建出一个子进程, 子进程返回。 父进程返回子进程的, 。 - wait, 等待一个进程完全停止
。 - exec, 用一个新的程序
完全替换掉当前进程, 。
一种实现重定向的方式
有限直接执行机制
操作进程是如何执行一个进程的
限制操作
但是这样做之后
为了防止这样的情况发生
系统调用的实现是通过
一次带系统调用的程序执行路径是这样的
- 操作系统启动时
初始化, CPU。 。 - 操作系统从硬盘中将程序加载到内存中
并分配堆栈空间, 寄存器, 初始化进程状态, 进入用户态, 跳转到程序的, 。 - 进程执行到系统调用时
通过, 陷入内核态, 操作系统保存进程的寄存器等信息。 执行对应的操作, 。 - 当操作系统执行完时
将保存的进程上下文恢复, 返回用户态, 继续执行对应的程序, 。 - 进程执行完后
执行系统调用, - 操作系统清理进程的状态
内存、 。
中断执行
当
解决这个问题
操作系统如果需要主动的掌握控制权
切换线程执行是一次上下文切换的过程
当一次中断发生时
调度策略 (policies)
OS
关于任务
- 所有任务运行相等时间
- 所有任务启动的时间一致
- 启动任务后
任务必须执行完, 。 - 任务只使用
。 - 操作系统知道所有进程的需要消耗的时间
。
有两种指标
- 周转时间
turnaround time( ) 任务完成时间减去任务到达时间, 。 - 响应时间
Response Time( ) 第一次运行减去任务到达时间, 。
FIFO
先到达先处理
当
SJF
去掉假设
先执行消耗时间最短的任务
STCF
去掉假设
抢占式的算法
先执行完成时间最短的任务
RR
引入响应时间作为关注指标
每个任务执行一个时间片
允许 Overlap
去掉假设
将每个中间有
多级反馈队列调度算法
去掉假设
思路
- 当任务
任务, 。 - 当两个任务优先级相等时
两个任务以, 。 - 当任务到达时
放入最高优先级队列中, 。 - 如果任务在当前队列的时间片配额用完后
被移入低一个等级的队列中, 。 - 每过一段时间
所有任务都被移入最高优先级的队列中, 。