异常控制流一(进程与进程的上下文切换)

一、正常控制流

(1)按顺序取下一条指令执行

(2)通过call,ret,jmp,jcc等指令跳转到转移目标地址处执行

cpu控制流是什么?

cpu所执行的指令的地址序列。

二、异常控制流

1.分类

①内部异常(硬件层)

整除0,溢出,缺页,越级,越权

②外部中断(硬件层)

打印机缺纸,ctrl+c,DMA结束等

③进程上下文切换(操作系统层)

 

2.程序和进程

程序

按某种方式形成的代码和数据的集合,静态的概念。

进程

  • 程序关于某个数据集合的一次运行活动。动态的含义。不同的数据不同的进程。
  • 操作系统以外的都属于“用户”的任务。
  • 计算机所有“任务”由进程完成。

为什么引入进程?

  • 一个独立的逻辑控制流,好像独占计算机资源。
  • 一个私有的虚拟地址空间,好像独占存储器。
  • 简化了编程,编译,链接,共享,加载。

3.逻辑控制流

对于确定的数据集,某进程的指令执行地址序列是确定的。称为进程的逻辑控制流。

单处理器系统:轮流使用处理器,处理器的物理控制流由多个进程的逻辑控制流组成。

 并发:不同的进程控制流在时间上交错或者重叠的情况。 p1和p2、p2和p3是并发执行。

4.进程的上下文切换

问题: 

hello程序何时被装入的?谁来装入?被谁启动?每次装到相同的地方?hello是否知道还有其他程序同时运行?

①进程的上下文切换

OS通过处理器调度让处理器轮流执行多个进程,实现不同进程中指令交替执行的机制。

处理器的调度等事件会形成异常控制流,上下文切换实现了安全转换。

②进程的上下文

进程的物理实体(代码和数据),和支持进程运行的环境。

现场信息:寄存器内容。 (寄存器上下文、硬件上下文)

③进程的地址空间

 

 

5.进程的存储器映射

 每个进程的虚拟地址空间相同。

OS要管理进程,如何描述一个进程的地址空间?

①存储器映射:虚拟空间中一个区域,与硬盘上一个对象建立关联(生成页表项),并初始化一个vm_area_struct结构信息。

 

mmap函数实现存储器映射: 

void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offset);

 如何获得实参?读取可执行文件中的程序头表。

可执行文件到主存不能直接映射。

  •  磁盘上:可执行文件中的程序头表,描述了可执行文件区域到虚拟地址空间的映射信息。
  • 装入系统执行,生成进程:通过进程描述符中的链表,建立虚拟地址空间的区域,与可执行文件区域的关联。
  • 页表:描述了虚拟地址空间的page到主存page frame之间的映射。

6.共享对象和私有的写时拷贝对象

①可用mmap实现存储器映射

void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offset);

 功能:将指定文件fd中偏移量offset开始的长度为length个字节的一块信息,映射到虚拟空间中起始地址为start、长度为length个字节的一块区域,得到vm_area_struct结构的信息,并初始化相应页表项(P=0) ,建立文件地址和虚存区域之间的映射关系。

进程运行时,第一次访问这些页面时,会发生缺页(P=0),由缺页处理程序进行文件读写(P=1)。

prot指定该区域内页面的访问权限位,对应vm_area_struct结构中的vm_prot字段
PROT_EXE:页面内容由指令组成
PROT_READ:区域内页面可读
PROT_WRITE:区域内页面可写
PROT_NONE:区域内页面不能被访问

flags指定所映射的对象的类型,对应vm_area_struct结构中的vm_flags字段
MAP_PRIVATE :私有对象,采用写时拷贝技术,对应可执行文件中只读代码区域(.init、 .text、 .rodata )和已初始化数据区域( .data )
MAP_SHARED :共享对象,对应共享库文件中的信息
MAP_ANON :请求0的页,对应内核创建的匿名文件,相应页框用0初始化并驻留内存
MAP_PRIVATE | MAP_ ANON :未初始化数据(.bss).堆和用户栈等对应区域

②Linux虚拟地址空间中的区域

③共享对象

所有的进程都可以访问的代码和数据。

进程1运行,缺页,内核为进程1分配若干页框。

进程2运行时,缺页,发现这个磁盘中该区域已经在主存分配过页框,于是找到进程1页表项,将页框号填到进程2的页框号处。

即一个进程对共享区域的写操作对其他共享这个区域的进程都可见。 

④私有对象的写时拷贝对象。

  • 一个副本,多个进程使用,发生写的时候才拷贝。
  • 为什么采用写时拷贝?节省主存。 同一个可执行文件的不同进程,只读代码区一样,可读可写数据区开始时也一样,但是私有对象。
  • 进程1运行,缺页,内核为进程1分配若干页框。
  • 进程2运行时,缺页,发现这个磁盘中该区域已经在主存分配过页框,于是找到进程1页表项,将页框号填到进程2的页框号处,标记为只读
  • 如果都只是只读或者执行,则只有一个副本。
  • 若进程2写操作,发生访问违例,内核判断异常原因是进程试图写私有的写诗拷贝页,就分配一个新页框,吧内容拷贝过去,并修改。

7.异常、中断和输入/输出

OS管理程序执行,有时候处理器执行内核代码。用一个模式位表示用户代码和内核代码。

处理器分为用户模式(用户态)和内核模式(核心态)

  • 用户模式(目态,用户态):处理器运行用户进程,不允许使用特权指令
  • 内核模式(系统模式,管理模式,超级用户模式,管态,内核态,核心态):允许使用特权指令(停机,开/关中断,cache flush等)

8.程序的加载和运行

  • UNIX/Linux系统中可调用exeve()启动加载器 。
  • 功能:在当前进程上下文中加载并运行一个新程序。
  • 用法:int execve(char *filename, char *argv[],*envp[]);   filename加载运行的程序名,argv参数列表,evnp环境变量列表。错误,返回-1,控制权交给调用程序;成功,不返回,最终控制权交传递到可执行目标中main。
  • int main(int argc, char **argv, char **envp);或者int main(int argc, char *argv[], char *envp[]);argc参数个数,参数列表中第一个总是命令名(可执行文件名)

shell命令提示符下输入:Unix>ld -o test main.o test.o

①$./hello[enter]

②shell命令行构建了argv和envp

③调用fork()创建一个子进程,与父进程shell完全相同(只读/共享)

④调用execve()函数,在当前进程上下文中加载并运行hello,将hello中的,text节、.data节、.bss节等内容加载到当前进程的虚拟地址空间(仅修改当前进程上下文中关于存储映像的一些数据结构,如页表,不从此盘拷贝代码和数据等内容)

⑤调用hello的main,hello开始在一个进程的上下文中运行。

  • 通过调用execve调用加载器
  • loader根据可执行文件中的程序头表信息,将可执行文件的代码和数据从磁盘“拷贝”到存储器中(实际不真正拷贝,仅建立一种映像)
  • 加载后,将PC指向Entry point(即_start处),最终执行main函数,以启动程序执行

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hnu哈哈

请接受直女的么么哒????

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值