1、系统调用和过程(函数)调用的区别
调用形式:过程(函数)使用一般调用指令,其转向地址是固定不变的,包含在跳转语句中;但系统调用中不包含处理程序入口,而仅仅提供功能号,按功能号调用。
被调用代码位置不同:过程调用是一种静态调用,调用者和调用代码在同一程序内,经过连接编辑后作为目标代码一部分。系统调用是一种动态调用,系统调用的处理代码在调用程序之外(操作系统中)。
提供方式:过程调用往往由编译系统提供,不同编译系统提供的过程可以不同;系统调用由操作系统提供,一旦操作系统设计好,系统调用的功能、数量种类便固定不变。
调用实现:程序使用一般机器指令(跳转指令)来调用过程(函数),是在用户态运行的;程序执行系统调用,是通过中断机构来实现,需要从用户态转变到核心态,在管理状态执行,因此,安全性好。
2、系统调用控制程序的过程
取系统调用号,校验合法性;根据系统调用号定位核心函数地址;根据通用寄存器内容,从用户栈取入口参数;核心函数执行,结果返回。
3、用户态向内核态转换的情况
一个是程序请求操作系统服务程序;二是程序运行时产生的中断调用。
4、Linux的中断处理
快中断 & 慢中断
1)处理慢中断前需保存所有寄存器的内容,而快中断处理最初保存现场时,仅要保存那些被常规C 函数修改的寄存器;
2)在慢中断处理时,通常不屏蔽其他中断信号,而快中断处理时会屏蔽所有其他中断;
3)慢中断处理完毕后,通常不立即返回被中断的进程,而是进入调度程序重新进行调度,调度结果未必是被中断的进程运行(是抢先式调度)。而快中断处理完毕后,通常恢复现场返回被中断的进程继续执行(是非抢先式调度)。
底半处理
这种一部分工作由核心代码在关中断状态下处理,另外一部分工作由中断服务程序在开中断状态下来处理的方式称为底半处理(bottom half handling),Linux 用底半处理机制来实现中断事件的快速处理。
5、进程上下文
操作系统中把进程物理实体和支持进程运行的环境合称为进程上下文(process context)。在操作系统中,进程上下文包括三个组成部分:
用户级上下文(user -level context):由用户进程的程序块、用户数据块(含共享数据块)和用户堆栈组成的进程地址空间。
系统级上下文(system -level context):包括进程的标识信息、现场信息和控制信息,进程环境块,以及系统堆栈等组成的进程地址空间。
寄存器上下文(register context):由程序状态字寄存器、各类控制寄存器、地址寄存器、通用寄存器、用户栈指针等组成。
6、进程队列及其管理
7、进程切换与模式切换
中断是激活操作系统的唯一方法。
内核在四种情况下允许发生上下文切换:
(1) 当进程进入等待态时;
(2) 当进程完成其系统调用返回用户态但不是最有资格获得CPU 时;
(3) 当内核完成中断处理,进程返回用户态但不是最有资格获得CPU 时;
(4) 当进程执行结束时。
用户态到核心态或者核心态到用户态的转变是CPU 模式的改变,而不是进程上下文切换。
当中断发生的时候,暂时中断正在执行的用户进程,把进程从用户状态切换到内核状态,去执行操作系统例行程序以获得服务,这就是一次模式切换,注意,此时仍在该进程的上下文中执行,仅仅模式变了。内核在被中断了的进程的上下文中对这个中断事件作处理,即使该中断事件可能不是此进程引起的。
模式切换的步骤如下:
保存被中断进程的处理器现场信息。
根据中断号置程序计数器。
把用户状态切换到内核状态,以便执行中断处理程序。
8、进程阻塞步骤
停止进程执行,保存现场信息到PCB
修改进程控制块的相关内容,如进程状态由运行改为等待
把修改状态后的进程控制块加入相应的等待进程队列
转入进程调度程序调度其他进程
9、进程唤醒步骤
从相应的等待进程队列取出进程控制块
修改进程控制块相关信息,如进程状态由等待修改为运行
把修改后的进程控制块加入到就绪进程队列
10、进程创建和停止
创建进程的系统调用sys_fork( )和sys_clone 都通过调用do_fork( )函数来完成进程的创建。在do_fork( )函数中,首先分配进程控制块task_struct 的内存和进程所需的堆栈,并检测系统是否可以增加新的进程;然后,拷贝当前进程的内容,并对一些数据成员进行初始化;再为进程的运行做准备;最后,返回生成的新进程的进程标识号(pid)。如果进程是根据sys_clone( )产生的,那么,它的进程标识号就是当前进程的进程标识号,并且对于进程控制块中的一些成员指针并不进行复制,而仅仅把这些成员指针的计数count 增加1。这样,父子进程可以有效地共享资源。
进程终止的系统调用sys_exit( )通过调用do_exit( )函数实现。函数do_exit( )首先释放进程占用的大部分资源,然后进入TASK_ZOMBIE 状态,调用exit_notify( )通知父子进程,调用schedule( )重新调度。
11、单线程进程存在的问题
进程时空的开销大,频繁的进程调度将耗费大量处理器时间,要为每个进程分配存储空间限制了操作系统中进程的总数。
进程通信的代价大,每次通信均要涉及通信进程之间或通信进程与操作系统之间的信息传递。
进程之间的并发性粒度较粗,并发度不高,过多的进程切换和通信延迟使得细粒度的并发得不偿失。
不适合并行计算和分布并行计算的要求,对于多处理器和分布式的计算环境来说,进程之间大量频繁的通信和切换,会大大降低并行度。
不适合客户/服务器计算的要求。对于C/S 结构来说,那些需要频繁输入输出并同时大量计算的服务器进程(如数据库服务器、事务监督程序)很难体现效率。
12、进程模型
13、多线程进程中术语概念
进程的定义:进程是操作系统中进行保护和资源分配的基本单位。
线程是操作系统进程中能够独立执行的实体(控制流),是处理器调度和分派的基本单位。(并发性、共享性、动态性、结构性)
内核级线程KLT(Kernel Level Threads)
在多处理器上,内核能够同时调度同一进程中多个线程并行执行;
若进程中的一个线程被阻塞了,内核能调度同一进程的其他线程占有处理器运行,也可以运行其他进程中的线程。
由于内核线程仅有很小的数据结构和堆栈,KLT 的切换比较快,内核自身也可以用多线程技术实现,从而,
能提高系统的执行速度和效率
KLT 的主要缺点是:应用程序线程在用户态运行,而线程调度和管理在内核实现,在同一进程中,控制权从一个线程传送到另一个线程时需要用户态-内核态-用户态的模式切换,系统开销较大。
14、作业调度算法
先来先服务FCFS(First Come,First Served)算法
最短作业优先SJF(Shortest Job First )算法