中断和异常的处理机制
都具有硬件和软件的处理过程,合在一起才能完成操作系统的一个具体的服务
为了区分异常、终端的来源,需要模拟出一个类似于键值对的数据,key是中断号或异常号,区分出键盘还是鼠标。中断与异常都是打断一个应用程序的运行去处理一个更加紧急的事件,而为了保证应用程序的安全,就必须有保存与恢复机制,以保证应用程序完成中断与异常之后继续运行。
完成中断或异常分为两部分,一个是硬件,一个是软件
中断
- 硬件部分
设置中断标记[CPU初始化]
1.将内部、外部事件设置中断标记
2.中断事件ID
依据这些信息来找到需要处理的进程 - 软件部分(指操作系统)
1.保存当前处理状态或保存现场(程序执行进度、内容;便于回复程序后继续往下执行)
2.根据CPU提供的中断号跳到中断地址去执行,这个过程中根据外设的具体情况完成相应的操作
3.处理完成之后,清除中断标记
4.恢复之前保存的处理状态
异常
- 出现异常后得到异常编号
1.保存现场
2.根据异常编号处理异常 - 1.如果异常的指令是不再执行程序,那就会杀死产生异常的程序
- 2.如果OS判断是OS的服务所产生的问题,进行服务弥补工作,而后重新执行异常指令
3.回复现场
系统调用
系统调用来源于应用程序需要OS提供一些服务,应用程序于OS之间需要一个接口,这个接口名字就是系统调用接口
比如一个程序需要用户输入字符串,而后将字符串输出,这个过程中就触发了一个系统调用,就是write系统调用,这个调用会携带一些参数,包含用哪些设备显示字符串以及字符串的内容,回去参数后进行对设备的访问
程序访问主要是通过高层次的API接口而不是直接进行系统调用
- Win32 API用于Windows
- POSIX(通用可移植) API用于POSIX-based systems(包括UNIX、LINUX、MacOS X的所有版本)
- Java API用于JAVA虚拟机(JVM 这些API不是系统调用,这只是java虚拟机提供的一些支持,做中还是会通过类似于Win32 API或POSIX API来实现相应的系统调用的服务)
操作系统如何实现系统调用(System Call)
应用程序通过接口进行系统调用,一旦使用接口,会触发一种特殊的命令,使操作系统的特权级发生改变,即用户态与内核态的转变
- 用户态:特权级别很低,对于一些特殊的机器指令和I/O进行访问
- 内核态:特权级很高,可以访问一些特权指令等等
- 这种特权级的转换使得OS的安全性得到提高
系统调用与函数调用的区别
- 函数调用是在同一个栈空间完成参数的调用、传递、返回;而系统调用的过程中,内核操作系统和应用程序拥有各自的堆、栈,也就是说,当应用程序发出系统调用之后,奇幻到内核执行时需要切换堆栈,同时完成特权级发生转换时,这个过程造成高于函数调用的开销(时间),回报是安全性的提高
总结
异常、中断、系统调用的过程,实现了跨越操作系统与应用程序、操作系统与外设的边界;过程中产生了开销,但却是提高了操作系统的安全性和可靠性
跨越操作系统边界的开销
- 在执行时间上的开销超过程序调用
- 开销:
- 1.建立中断、异常、系统调用的代号与对应服务例程映射关系的初始化开销(建立出对应关系表)
- 2.建立内核堆栈(操作系统有自己的堆栈,不能与应用程序的堆栈混合;所以要对这个堆栈进行维护,也就是操作系统退出时要把这部分堆栈保存,操作系统进入时,要把这部分堆栈恢复)
- 3.验证参数(应用程序发出请求时会携带一些关于外设、数据等参数,OS对这些参数进行检查)
- 4.内核态映射到用户台的地址空间,更新页面映射权限(操作系统处理某些数据之后,会将这些数据从内核态导入到用户态,这个过程是一个拷贝的过程)
- 5.内核态独立空间地址
- 这些开销使得操作系统能够保证其在一个安全可靠的环境中执行