在给进程下定义以前,先总结一下第一、2章介绍的一些概念:算法
有了应用程序、系统软件和资源的概念,就能够讨论操做系统怎样以一个有序的方式管理应用程序的执行,以达到如下目的:数据库
全部现代操做系统采用的方法都是依据对应于一个或多个进程存在的应用程序执行的一种模型。小程序
第2章给进程下了如下几个定义:安全
也能够把进程当成由一组元素组成的实体,进程的两个基本的元素是程序代码(可能被执行相同程序的其余进程共享)和代码相关联的数据集。
假设处理器开始执行这个程序代码,且把这个执行实体叫作进程。
在进程执行时,任意给定一个时间,进程均可以惟一地被表征为如下元素:服务器
上述列表信息存放在一个叫作进程控制块(如图)的数据结构中,该控制块由操做系统建立和管理。进程控制块包含了充分的信息,这样就能够中断一个进程的执行,而且在后来恢复执行进程时就好像进程未被中断过。进程控制块是操做系统可以支持多进程和提供多处理的关键工具。当进程被中断时,操做系统会把程序计数器和处理器寄存器(上下文数据)保存到进程控制块中的相应位置,进程状态也被改变为其余的值,例如阻塞态或就绪态(后面将讲述)。操做系统能够把其余进程设置为运行态,把其余进程的程序计数器和进程上下文数据加载处处理器寄存器中,这样其余进程就能够开始执行了。网络
![]() |
图3.1 简化的进程控制块 |
所以,进程是由程序代码和相关数据还有进程控制块组成。对于一个单处理器计算机,在任什么时候间都最多只有一个进程在执行,正在运行的这个进程的状态为运行态。数据结构
正如前面所提到的,对一个被执行的程序,操做系统会为该程序建立一个进程或任务。并发
举例,图3.2 给出了三个进程在内存中的布局,为简化讨论,假设没有使用虚拟内存,所以全部三个进程都由彻底载入内存中的程序表示,此外,有一个小的分派器一1使处理器从一个进程切换到另外一个进程。图3.3 给出了这三个进程在执行过程早期的轨迹,给出了进程A 和C 中最初执行的12 条指令,进程B 执行4 条指令,假设第4 条指令调用了进程必须等待的I/O 操做。编辑器
![]() |
图3.2 在指令周期13 时的执 行快照(如图3.4 所示) |
如今从处理器的角度看这些轨迹。图3.4 给出了最初的52个指令周期中交替的轨迹(为方便起见,指令周期都给出了编号)。在图中,阴影部分表明由分配器执行的代码。在每一个实例中由分派器执行的指令顺序是相同的,由于是分派器的同一个功能在执行。假设操做系统仅容许一个进程最多连续执行6 个指令周期,在此以后将被中断,这避免了任何一个进程独占处理器时间。如图3.4 所示,进程A 最初的6 条指令被执行,接下来是一个超时并执行分派器的某些代码,在控制转移给进程B 以前分派器执行了6 条指令二2。在进程B 的4 条指令被执行后,进程B 请求一个它必须等待的I/O 动做,所以,处理器中止执行进程B,并经过分派器转移到进程C。在超时后,处理器返回进程A,当此次处理超时时,进程B 仍然等待那个I/O 操做的完成,所以分派器再次转移到进程C。模块化
![]() |
(点击查看大图)图3.3 图3.2 中进程的轨迹 |
![]() |
(点击查看大图)图3.4 图3.2 中进程的组合轨迹 |
操做系统的基本职责是控制进程的执行,这包括肯定交替执行的方式和给进程分配资源。在设计控制进程的程序时,第一步就是描述进程所表现出的行为。
任什么时候刻,一个进程能够处于如下两种状态之一:运行态或未运行态,如图3.5a 所示。当操做系统建立一个新进程时,它将该进程以未运行态加入到系统中,操做系统知道这个进程是存在的,并正在等待执行机会。当前正在运行的进程不时地被中断,操做系统中的分派器部分将选择一个新进程运行。前一个进程从运行态转换到未运行态,另一个进程转换到运行态。
从这个简单的模型能够意识到操做系统的一些设计元素。必须用某种方式来表示每一个进程,使得操做系统可以跟踪它,也就是说,必须有一些与进程相关的信息,包括进程在内存中的当前状态和位置,即进程控制块。未运行的进程必须保持在某种类型的队列中,并等待它们的执行时机。图3.5b 给出了一个结构,结构中有一个队列,队列中的每一项都指向某个特定进程的指针,或队列能够由数据块构成的链表组成,每一个数据块表示一个进程。
能够用该排队图描述分派器的行为。被中断的进程转移到等待进程队列中,或者,若是进程已经结束或取消,则被销毁(离开系统)。在任何一种状况下,分派器均从队列中选择一个进程来执行。
![]() |
图3.5 两状态进程模型 |
在对简单的两状态模型进行改进以前,讨论一下进程的建立和终止。不管使用哪一种进程行为模型,进程的生存期都围绕着进程的建立和终止。
进程的建立
当一个新进程添加到那些正在被管理的进程集合中去时,操做系统须要创建用于管理该进程的数据结构(见3.3 节),并在内存中给它分配地址空间。将在3.3 节中讲述这些数据结构,这些行为构成了一个新进程的建立过程。
一般有4 个事件会致使建立一个进程,如表。
不论在哪一种状况下,操做系统都负责新进程的建立;操做系统也可能会表明应用程序建立进程,eg:若是用户请求打印一个文件,则操做系统能够建立一个管理打印的进程,进而使请求进程能够继续执行,与完成打印任务的时间无关。
表3.1 致使进程建立的缘由
![]() |
传统地,操做系统建立进程的方式对用户和应用程序都是透明的。但容许一个进程引起另外一个进程的建立将是颇有用的。例如,一个应用程序进程能够产生另外一个进程,以接收应用程序产生的数据,并将数据组织成适合之后分析的格式。新进程与应用程序并行地运行,并当获得新的数据时被激活。这个方案对构造应用程序是很是有用的,例如,服务器进程(如打印服务器、文件服务器)能够为它处理的每一个请求产生一个新进程。当操做系统为另外一个进程的显式请求建立一个进程时,这个动做称为进程派生。
当一个进程派生另外一个进程时,前一个称作父进程,被派生的进程称作子进程。在典型的状况下,相关进程须要相互之间的通讯和合做。相关主题将在第5 章讲述。
进程终止
表3.2 归纳了进程终止的典型缘由。任何一个计算机系统都必须为进程提供表示其完成的方法,批处理做业中应该包含一个Halt 指令或用于终止的操做系统显式服务调用来终止。
表3.2 致使进程终止的缘由
![]() |
若是全部进程都作好了执行准备,则图3.5b 所给出的排队原则是有效的。队列是“先进先出”的表,对于可运行的进程处理器以一种轮转方式操做(依次给队列中的每一个进程必定的执行时间,而后进程返回队列,阻塞状况除外)。但即便对前面描述的简单例子,这个实现都是不合适的:存在着一些处于非运行状态但已经就绪等待执行的进程,而同时存在另外的一些处于阻塞状态等待I/O 操做结束的进程。所以,若是使用单个队列,分派器不能只考虑选择队列中最老的进程,相反,它应该扫描这个列表,查找那些未被阻塞且在队列中时间最长的进程。
解决这种状况的一种比较天然的方法是将非运行状态分红两个状态:就绪(ready)和阻塞(blocked),以下图。新图中的5 个状态以下:
![]() |
图3.6 五状态进程模型 |
新建状态对应于刚刚定义的进程。例如,若是一位新用户试图登陆到分时系统中,或者一个新的批做业被提交执行,那么操做系统能够分两步定义新进程。
相似地,进程退出系统也分为两步。
图3.6 显示了致使进程状态转换的事件类型。可能的转换以下:
再回到前面的简单例子,图3.7 显示了每一个进程在状态间的转换,图3.8a 给出了可能实现的排队规则,有两个队列:就绪队列和阻塞队列。进入系统的每一个进程被放置在就绪队列中,当操做系统选择另外一个进程运行时,将从就绪队列中选择。对于没有优先级的方案,这能够是一个简单的先进先出队列。当一个正在运行的进程被移出处理器时,它根据状况或者被终止,或者被放置在就绪或阻塞队列中。最后,当一个事件发生时,全部位于阻塞队列中等待这个事件的进程都被转换到就绪队列中。
![]() |
图3.7 图3.4 中的进程状态 |
后一种方案意味着当一个事件发生时,操做系统必须扫描整个阻塞队列,搜索那些等待该事件的进程。在大型操做系统中,队列中可能有几百甚至几千个进程,所以,拥有多个队列将会颇有效,一个事件能够对应一个队列。那么,当事件发生时,相应队列中的全部进程都转换到就绪态(见图3.8b)。
![]() |
(点击查看大图)图3.8 图3.6 的排队模型 |
最后还有一种改进是,若是按照优先级方案分派进程,维护多个就绪队列(每一个优先级一个队列)将会带来不少的便利。操做系统能够很容易地肯定哪一个就绪进程具备最高的优先级且等待时间最长。
交换的须要
前面描述的三个基本状态(就绪态、运行态和阻塞态)提供了一种为进程行为创建模型的系统方法,但能够证实往模型中增长其余状态也是合理的。为了说明加入新状态的好处,考虑一个没有使用虚拟内存的系统,每一个被执行的进程必须彻底载入内存,所以,图3.8b 中,全部队列中的全部进程必须驻留在内存中。
全部这些设计机制的缘由都是因为I/O 活动比计算速度慢不少,所以在单道程序系统中的处理器在大多数时候是空闲的。可是图3.8b 的方案并无彻底解决这个问题。在这种状况下,内存保存有多个进程,当一个进程正在等待时,处理器能够转移到另外一个进程,可是处理器比I/O要快得多,以致于内存中全部的进程都在等待I/O 的状况很常见。所以,即便是多道程序设计,大多数时候处理器仍然可能处于空闲状态。
一种解决方法是内存能够被扩充以适应更多的进程,可是这种方法有两个缺陷。
另外一种解决方案是交换,包括把内存中某个进程的一部分或所有移到磁盘中。当内存中没有处于就绪状态的进程时,操做系统就把被阻塞的进程换出到磁盘中的“挂起队列”。操做系统在此以后取出挂起队列中的另外一个进程,或者接受一个新进程的请求,将其归入内存运行。进程行为模型(见图3.9a)中增长另外一个状态:挂起态。
“交换”是一个I/O 操做,于是也可能使问题更加恶化。可是因为磁盘I/O 通常是系统中最快的I/O(相对于磁带或打印机I/O),因此交换一般会提升性能。
当操做系统已经执行了一个换出操做,它能够有两种将一个进程取到内存中的选择:
一般比较倾向于调入一个之前被挂起的进程,给它提供服务,而不是增长系统中的负载总数。
但全部已经挂起的进程在挂起时都处于阻塞态。显然,这时把被阻塞的进程取回内存没有任何意义,由于它仍然没有准备好执行。可是,挂起状态中的每一个进程最初是阻塞在一个特定的事件上,当这个事件发生时,进程就再也不阻塞,能够继续执行。所以,须要从新考虑设计方式。有两个独立的概念:进程是否在等待一个事件(阻塞与否)以及进程是否已经被换出内存(挂起与否)。为适应这种2×2 的组合,须要4 个状态:
![]() |
图3.9 有挂起态的进程状态转换图 |
在查看包含两个新挂起状态的状态转换图以前,必须提到另外一点。到如今为止的论述都假设没有使用虚拟内存,进程或者都在内存中,或者都在内存以外。在虚拟内存方案中,可能会执行到只有一部份内容在内存中的进程,若是访问的进程地址不在内存中,则进程的相应部分能够被调入内存。虚拟内存的使用看上去会消除显式交换的须要,这是由于经过处理器中的存储管理硬件,任何指望的进程中的任何指望的地址均可以移入或移出内存。可是,正如在第8 章中将会看到的,若是有足够多的活动进程,而且全部进程都有一部分在内存中,则有可能致使虚拟内存系统崩溃。所以,即便在虚拟存储系统中,操做系统也须要不时地根据执行状况显式地、彻底地换出进程。
如今来看图3.9b 中咱们已开发的状态转换模型(图中的虚线表示可能但并非必需的转换)。比较重要的新的转换以下:
还须要考虑的几种其余转换有:
挂起的其余用途
到目前为止,挂起进程的概念与不在内存中的进程概念是等价的。一个不在内存中的进程,不论它是否在等待一个事件,都不能当即执行。
咱们能够总结一下挂起进程的概念。首先,按照如下特色定义挂起进程:
表3.3 列出了进程的一些挂起缘由。
另一些缘由关系到交互用户的行为。例如,若是用户怀疑程序中有缺陷,他(她)能够挂起执行程序并进行调试,检查并修改程序或数据,而后恢复执行;或者可能有一个收集记录或记帐的后台程序,用户可能但愿可以打开或关闭这个程序。
表3.3 致使进程挂起的缘由
![]() |
时机的选择也会致使一个交换决策。例如,若是一个进程周期性地被激活,但大多数时间是空闲的,则在它在两次使用之间应该被换出。监视使用状况或用户活动的程序就是一个例子。
最后,父进程可能会但愿挂起一个后代进程。例如,进程A 能够生成进程B,以执行文件读操做;随后,进程B 在读文件的过程当中遇到错误,并报告给进程A;进程A 挂起进程B,调查错误的缘由。
在全部这些状况中,挂起进程的活动都是由最初请求挂起的代理请求的。
操做系统控制计算机系统内部的事件,它为处理器执行进程而进行调度和分派,给进程分配资源,并响应用户程序的基本服务请求。所以,咱们能够把操做系统看作是管理系统资源的实体。
这个概念如图3.10 所示。在多道程序设计环境中,在虚拟内存中有许多已经建立了的进程,每一个进程在执行期间,须要访问某些系统资源,包括处理器、I/O 设备和内存。在图中,进程P1 正在运行,该进程至少有一部分在内存中,而且还控制着两个I/O 设备;进程P2 也在内存中,但因为正在等待分配给P1 的I/O 设备而被阻塞;进程Pn 已经被换出,所以是挂起的。
之后几章中将探讨操做系统表明进程管理这些资源的细节。这里关心的是一些最基本的问题:操做系统为了控制进程和管理资源须要哪些信息?
![]() |
图3.10 进程和资源(某一时刻的资源分配) |
操做系统为了管理进程和资源,必须掌握关于每一个进程和资源当前状态的信息。广泛使用的方法是:操做系统构造并维护它所管理的每一个实体的信息表。如图3.11,操做系统维护着4 种不一样类型的表:内存、I/O、文件和进程。
![]() |
图3.11 操做系统控制表的通用结构 |
1、内存表用于跟踪内(实)存和外存(虚拟内存)。内存的某些部分为操做系统而保留,剩余部分是进程可使用的,保存在外存中的进程使用某种类型的虚拟内存或简单的交换机制。内存表必须包括如下信息:
第三部分将详细讲述用于内存管理的信息结构。
2、操做系统使用I/O 表管理计算机系统中的I/O 设备和通道。在任何给定的时刻,一个I/O 设备或者是可用的,或者已分配给某个特定的进程,若是正在进行I/O 操做,则操做系统须要知道I/O 操做的状态和做为I/O 传送的源和目标的内存单元。在第11 章将详细讲述I/O 管理。
3、操做系统维护着文件表,这些表提供关于文件是否存在、文件在外存中的位置、当前状态和其余属性的信息。大部分信息(不是所有信息)可能由文件管理系统维护和使用。在这种状况下,操做系统只有一点或者没有关于文件的信息;在其余操做系统中,不少文件管理的细节由操做系统本身管理。这方面的内容将在第12 章讲述。
4、最后,操做系统为了管理进程必须维护进程表。须要先明确两点:首先,尽管图3.11 给出了4 种不一样的表,可是这些表必须以某种方式连接起来或交叉引用。内存、I/O 和文件是表明进程而被管理的,所以进程表中必须有对这些资源的直接或间接引用。文件表中的文件能够经过I/O 设备访问,有时它们也位于内存中或虚拟内存中。这些表自身必须能够被操做系统访问到,所以它们受制于内存管理。
其次,操做系统最初如何知道建立表?显然,操做系统必须有基本环境的一些信息,若有多少内存空间、I/O 设备是什么以及它们的标识符是什么等。这是一个配置问题,也就是说,当操做系统初始化后,它必须可使用定义基本环境的某些配置数据,这些数据必须在操做系统以外,经过人的帮助或一些自动配置软件而产生。
操做系统在管理和控制进程时,首先必须知道进程的位置以及在管理时所必需的进程属性(如进程ID、进程状态)。
进程位置
进程的物理表示是什么?
程序、数据、栈和属性的集合称作进程映像(process image)(见表3.4进程映像中的典型元素)。
![]() |
进程映像的位置依赖于使用的内存管理方案。
最简单的状况,进程映像保存在邻近的或连续的存储块中。该存储块位于外存(一般是磁盘)中。若是操做系统要管理进程,其进程映像至少有一部分必须位于内存中,为执行该进程,整个进程映像必须载入内存中或至少载入虚拟内存中。所以,操做系统须要知道每一个进程在磁盘中的位置,而且对于内存中的每一个进程,须要知道其在内存中的位置。来看一下第2 章中CTSS 操做系统关于这个方案的一个稍微复杂些的变体。在CTSS 中,当进程被换出时,部分进程映像可能保留在内存中。所以,操做系统必须跟踪每一个进程映像的哪一部分仍然在内存中。
现代操做系统假定分页硬件容许用不连续的物理内存来支持部分常驻内存的进程。在任何给定的时刻,进程映像的一部分能够在内存中,剩余部分能够在外存中。所以,操做系统维护的进程表必须代表每一个进程映像中每页的位置。
图3.11 描绘了位置信息的结构。有一个主进程表,每一个进程在表中都有一个表项,每一项至少包含一个指向进程映像的指针。若是进程映像包括多个块,则这个信息直接包含在主进程表中,或能够经过交叉引用内存表中的项获得。固然,这个描述是通常性描述,特定的操做系统将按本身的方式组织位置信息。
进程属性
每一个进程的大量信息该信息能够保留在进程控制块中。不一样的系统以不一样的方式组织该信息。表3.5( 进程控制块中的典型元素) 列出了每一个进程信息的简单分类。
能够把进程控制块信息分红三类:
![]() |
![]() |
1、每一个进程都分配了一个惟一的数字标识符。进程标识符能够简单地表示为主进程表(图3.11 所示)中的一个索引;不然,必须有一个映射,使得操做系统能够根据进程标识符定位相应的表。操做系统控制的许多其余表可使用进程标识符交叉引用进程表。例如,内存表能够组织起来以便提供一个关于内存的映射,指明每一个区域分配给了哪一个进程。I/O 表和文件表中也会有相似的引用。当进程相互之间进行通讯时,进程标识符可用于通知操做系统某一特定通讯的目标;当容许进程建立其余进程时,标识符可用于指明每一个进程的父进程和后代进程。
除了进程标识符,还给进程分配了一个用户标识符,用于标明拥有该进程的用户。
2、处理器状态信息包括处理器寄存器的内容。当一个进程正在运行时,其信息固然在寄存器中。当进程被中断时,全部的寄存器信息必须保存起来,使得进程恢复执行时这些信息均可以被恢复。所涉及的寄存器的种类和数目取决于处理器的设计。在典型状况下,寄存器组包括用户可见寄存器、控制和状态寄存器和栈指针,这些在第1 章中都曾介绍过。
处理器都包括一个或一组一般称作程序状态字( PSW)的寄存器,它包含状态信息。PSW 一般包含条件码和其余状态信息。Pentium处理器中的处理器状态字就是一个很好的例子,它称作EFLAGS 寄存器(如图3.12 和表3.6 所示),可被运行在Pentium 处理器上的任何操做系统(包括UNIX 和Windows)使用。
3、进程控制信息是操做系统控制和协调各类活动进程所须要的额外信息。表3.5 代表了这类信息的范围,随后章节将进一步详细分析。
图3.13 给出了虚拟内存中进程映像的结构。每一个进程映像包括一个进程控制块、用户栈、进程的专用地址空间以及与别的进程共享的任何其余地址空间。在这个图中,每一个进程映像表现为一段地址相邻的区域。在实际的实现中可能不是这种状况,这取决于内存管理方案和操做系统组织控制结构的方法。
![]() |
图3.12 PentiumⅡEFLAGS 寄存器 |
表3.6 Pentium EFLAGS 寄存器位
![]() |
正如表3.5 中所指出的,进程控制块还可能包含构造信息,包括将进程控制块连接起来的指针。所以,前一节中所描述的队列能够由进程控制块的链表实现,例如,图3.8a 中的排队结构能够按图3.14 中的方式实现。
进程控制块的做用
每一个进程控制块包含操做系统所须要的关于进程的全部信息。实际上,操做系统中的每一个模块,包括那些涉及调度、资源分配、中断处理、性能监控和分析的模块,均可能读取和修改它们。能够说,资源控制块集合定义了操做系统的状态。
![]() |
(点击查看大图)图3.13 虚拟内存中的用户进程 |
操做系统中的不少例程都须要访问进程控制块中,直接访问这些表并不难,每一个进程都有一个惟一ID 号,可用做进程控制块指针表的索引。困难的不是访问而是保护,具体表现为下面两个问题:
这些问题能够经过要求操做系统中的全部例程都经过一个处理例程来专门处理,处理例程的任务仅仅是保护进程控制块,它是读写这些块的惟一的仲裁程序。使用这类进程,须要权衡性能问题和对系统软件剩余部分正确性的信任程度。
![]() |
图3.14 进程链表结构 |
首先需区分“与操做系统相关联的”以及“与用户程序相关联”的处理器执行模式。
某些指令只能在特权态下运行,包括读取或改变诸如程序状态字之类控制寄存器的指令、原始I/O 指令和与内存管理相关的指令。另外,有部份内存区域仅在特权态下能够被访问到。
表3.7 操做系统内核的典型功能
![]() |
使用两种模式的缘由:保护操做系统和重要的操做系统表(如进程控制块)不受用户程序的干涉。在内核态下,软件具备对处理器以及全部指令、寄存器和内存的控制能力,这一级的控制对用户程序不是必需的,且为了安全起见也不是用户程序可访问的。
这样产生了两个问题:处理器如何知道它正在什么模式下执行以及如何改变这一模式。
对第一个问题,程序状态字中有一位表示执行模式,这一位应某些事件的要求而改变。在典型状况下,当用户调用一个操做系统服务或中断触发系统例程的执行时,执行模式被设置成内核态,当从系统服务返回到用户进程时,执行模式被设置为用户态。例如64 位IA-64 体系结构的Intel Itanium 处理器,有一个处理器状态寄存器(PSR),包含2 位的CPL(当前特权级别)域,级别0 是最高特权级别,级别3 是最低特权级别。大多数操做系统,如Linux,使用级别0 做为内核态,使用另外一个级别做为用户态。当中断发生时,处理器清空大部分PSR 中的位,包括CPL域,这将自动把CPL 设置为0。在中断处理例程结束时,最后的一个指令是irt(中断返回),这条指令使处理器恢复中断程序的PSR 值,也就是恢复了程序的特权级别。当应用程序调用一个系统调用时,会发生相似的状况。对于Itanium,应用程序使用系统调用是经过如下方式实现的:把系统调用标识符和参数放在一个预约义的区域,而后经过执行一个特殊的指令中断用户态程序的执行,并把控制权交给内核。
讨论了与进程相关的数据结构后,可简单描述实际建立进程时的步骤。
一旦操做系统决定基于某种缘由(见表3.1)建立一个新进程,可按如下步骤进行:
表面看进程切换的功能是简单的。某一时刻,一个正在运行的进程被中断,操做系统指定另外一个进程为运行态,并把控制权交给这个进程。
什么时候切换进程
进程切换在操做系统从当前正在运行的进程中得到控制权的任什么时候刻发生。表3.8 给出了可能把控制权交给操做系统的事件。
1、系统中断。大多数操做系统区分两种类型的系统中断:
对于普通中断,控制首先转移给中断处理器,它作一些基本的辅助工做,而后转到与已经发生的特定类型的中断相关的操做系统例程。参见如下例子:
2、对于陷阱,操做系统肯定错误或异常条件是不是致命的。若是是,当前正在运行的进程被转换到退出态,并发生进程切换;若是不是,操做系统的动做取决于错误的种类和操做系统的设计,其行为能够是试图恢复或通知用户,操做系统可能会进行一次进程切换或者继续执行当前正在运行的进程。
3、操做系统可能被来自正在执行的程序的系统调用激活。例如,一个用户进程正在运行,而且正在执行一条请求I/O 操做的指令,如打开文件,这个调用致使转移到做为操做系统代码一部分的一个例程上执行。一般,使用系统调用会致使把用户进程置为阻塞态。
表3.8 进程执行的中断机制
![]() |
模式切换
中断阶段,处理器经过中断信号检查是否发生了任何中断。若没有未处理的中断,处理器继续取指令周期,即取当前进程中的下一条指令,若存在未处理的中断,处理器须要作如下工做:
处理器继续取指阶段,并取中断处理程序的第一条指令,它将给中断提供服务。此时,被中断的进程上下文保存在被中断程序的进程控制块中。
保存的上下文环境包括什么?全部中断处理可能改变的信息和恢复被中断程序时所须要的信息。所以,须保存称作处理器状态信息的进程控制块部分,这包括程序计数器、其余处理器寄存器和栈信息。
还须要作些其余工做吗?取决于下一步会发生什么。中断处理程序一般执行与中断相关的基本任务的小程序。例如,它重置表示出现中断的标志或指示器。可能给产生中断的实体如I/O 模块发送应答。它还作一些与产生中断的事件结果相关的基本辅助工做。例如,若是中断与I/O 事件有关,中断处理程序将检查错误条件;若是发生了错误,中断处理程序给最初请求I/O操做的进程发一个信号。若是是时钟中断,处理程序将控制移交给分派器,当分配给当前正在运行进程的时间片用尽时,分派器将控制转移给另外一个进程。
进程控制块中的其余信息如何处理?若是中断以后是切换到另外一个应用程序,则须要作一些工做。可是,在大多数操做系统中,中断的发生并非必须伴随着进程切换的。多是中断处理器执行以后,当前正在运行的进程继续执行。在这种状况下,所须要作的是当中断发生时保存处理器状态信息,当控制返回给这个程序时恢复这些信息。在典型状况下,保存和恢复功能由硬件实现。
进程状态的变化
显然,模式切换与进程切换是不一样的。发生模式切换能够不改变正处于运行态的进程状态,这种状况下,保存上下文环境和之后恢复上下文环境只须要不多的开销。可是,若是当前正在运行的进程被转换到另外一个状态(就绪、阻塞等),则操做系统必须使其环境产生实质性的变化,完整的进程切换步骤以下:
所以,进程切换涉及状态变化,于是比模式切换须要作更多的工做。
操做系统的两个特殊事实:
若操做系统仅仅是一组程序,那么操做系统是一个进程吗?若是是,如何控制它?这些有趣的问题列出了大量的设计方法,图3.15 给出了在当代各类操做系统中使用的各类方法。
老操做系统中,传统和通用的方法是在全部的进程以外执行操做系统内核(见图3.15a)。经过这种方法,在当前正运行的进程被中断或产生一个系统调用时,该进程的模式上下文环境被保存起来,控制权转交给内核。操做系统有本身的内存区域和系统栈,用于控制过程调用和返回。操做系统能够执行任何预期的功能,并恢复被中断进程的上下文,这将致使被中断的用户进程从新继续执行。或者,操做系统能够完成保存进程环境的功能,并继续调度和分派另外一个进程,是否这样作取决于中断的缘由和当前的状况。
不管哪一种状况,其关键点是进程的概念仅仅适用于用户程序,操做系统代码做为一个在特权模式下工做的独立实体被执行。
在较小的机器的操做系统中,常见的方法是在用户进程的上下文中执行几乎全部操做系统软件。其观点是操做系统从根本上说是用户调用的一组例程,在用户进程环境中执行,用于实现各类功能,如图3.15b 所示。在任什么时候刻,操做系统管理着n 个进程映像,每一个映像不只包括图3.13 中列出的区域,并且还包括内核程序的程序、数据和栈区域。
![]() |
图3.15 操做系统和用户进程的关系 |
图3.16 给出了这个策略下的一个典型的进程映像结构。当进程在内核态下时,独立的内核栈用于管理调用/返回。操做系统代码和数据位于共享地址空间中,被全部的用户进程共享。
![]() |
图3.16 进程映像:操做 系统在用户空间中执行 |
当发生一个中断、陷阱或系统调用时,处理器被置于内核态,控制权转交给操做系统。为了将控制从用户程序转交给操做系统,须要保存模式上下文环境并进行模式切换,而后切换到一个操做系统例程,但此时仍然是在当前用户进程中继续执行,所以,不须要执行进程切换,仅在同一个进程中进行模式切换。
若是操做系统完成其操做后,肯定须要继续运行当前进程,则进行一次模式切换,在当前进程中恢复被中断的程序。该方法的重要优势之一是,一个用户程序被中断以使用某些操做系统例程,而后被恢复,全部这些不用以牺牲两次进程切换为代价。若是肯定须要发生进程切换而不是返回到先前执行的程序,则控制权被转交给进程切换例程,这个例程可能在当前进程中执行,也可能不在当前进程中执行,这取决于系统的设计。在某些特殊的状况下,如当前进程必须置于非运行态,而另外一个进程将指定为正在运行的进程。为方便起见,这样一个转换过程在逻辑上能够看作是在全部进程以外的环境中被执行的。
在某种程度上,对操做系统的这种见解是很是值得注意的。在某些时候,一个进程能够保存它的状态信息,从就绪态进程中选择另外一个进程,并把控制权释放给这个进程。之因此说这是一种混杂的状况,是由于在关键时候,在用户进程中执行的代码是共享的操做系统代码而不是用户代码。基于用户态和内核态的概念,即便操做系统例程在用户进程环境中执行,用户也不能篡改或干涉操做系统例程。这进一步说明进程和程序的概念是不一样的,它们之间不是一对一的关系。在一个进程中,用户程序和操做系统程序都有可能执行,而在不一样用户进程中执行的操做系统程序是相同的。
图3.15c 中显示的是另外一种选择,即把操做系统做为一组系统进程来实现。与其余选择同样,做为内核一部分的软件在内核态下执行。不过在这种状况下,主要的内核函数被组织成独立的进程,一样,还可能有一些在任何进程以外执行的进程切换代码。
这种方法有几个优势。它利用程序设计原理,促使使用模块化操做系统,而且模块间具备最小的、简明的接口。此外,一些非关键的操做系统函数可简单地用独立的进程实现,例如,很早就曾经提到过的用于记录各类资源(处理器、内存、通道)的使用程度和系统中用户进程的执行速度的监控程序。因为这个程序没有为任何活动进程提供特定的服务,它只能被操做系统调用。做为一个进程,这个函数能够在指定的优先级上运行,而且在分派器的控制下与其余进程交替执行。最后,把操做系统做为一组进程实现,在多处理器或多机环境中都是十分有用的,这时一些操做系统服务能够传送到专用处理器中执行,以提升性能。
操做系统对于每一个进程都关联了一套权限。这些权限规定了进程能够获取哪些资源,包括内存区域、文件和特权系统指令等。典型的是,一个进程的运行表明着一个用户拥有操做系统认证的权限。在配置的时候,一个系统或者是一个实用进程就被分配了权限。
在一个典型的系统中,最高级别的权限指的是管理员、超级用户或根用户的访问权限。根用户的访问权限提供了对一个操做系统全部的功能和服务的访问。一个有着根用户访问权限的进程能够安全地控制一个系统,能够增长或者改变程序和文件,对其余进程进行监控,发送和接收网络流量和改变权限。
设计任何操做系统的一个关键问题是阻止或者至少是探测一个用户或者是一种恶意软件(恶意程序)得到系统受权的权限的企图,尤为是从根用户获取。本节,咱们将简短地总结关于这种安全问题的威胁和对策。在第七部分将对其作更加详细的阐述。
系统访问威胁分为两大类:入侵者和恶意软件。
入侵者
对于安全,一个最普通的威胁就是入侵者(另一个是病毒),一般是指黑客和解密高手。在早期的一项对入侵的重要研究中,Anderson [ANDE80] 定义了三种类型的入侵者:
冒充者:没有受权的我的去使用计算机和经过穿透系统的访问控制去使用一个合法用户的帐号。
滥用职权者:一个合法的用户访问没有受权的数据、程序或资源,或者用户具备这种访问的受权,可是滥用了他的权限。
秘密用户:一个用户得到了系统的管理控制,而后使用这种控制来逃避审计和访问控制,或者废止审查收集。
冒充者有可能就是外部人员;滥用职权者通常都是内部人员;秘密用户多是外部人员也多是内部人员。
入侵者的攻击有良性的也有严重的。在良性阶段,许多人仅仅是想浏览互联网并想知道在互联网上到底有什么。在严重阶段,这些人尝试着去读权限数据,修改未受权的数据或者是破坏系统。
入侵者的目的是得到一个系统的访问权限,或是增长一个系统的权限获取的范围。最初许多攻击是利用了系统或软件的漏洞,这些漏洞可让用户执行能够开启系统后门的代码。当程序以必定的权限运行,入侵者能够利用如缓冲溢出区攻击来得到系统的访问。将在7 章介绍缓冲区溢出攻击。
此外,入侵者也能够尝试获取那些已经被保护的信息。在一些状况下,信息就是在表框里面的用户密码。若是知道了一些用户的密码,那么入侵者能够登陆一个系统,而后运行合法用户的全部权限。
恶意软件
计算机系统最为复杂的威胁可能就是利用计算机系统漏洞的程序。这些威胁被称为恶意软件,或者是恶意程序。在这一部分,咱们将关注如编辑器、编译器和内核级程序等应用程序以及通用程序的威胁。
恶意软件分为两大类:一种须要宿主程序,一种则是独立的。对于前者,也被称为寄生,其本质上是一些不能独立于实际应用程序、通用程序或系统程序而存在的片断,例如病毒、逻辑炸弹和后门。后者则是独立并能够被操做系统调度和运行的程序,例如蠕虫和僵尸程序。
咱们也能够对这些软件威胁进行如下的区分:一种不能进行复制,而另一种则能够。前者是经过触发器激活的程序或者程序片断,例如,逻辑炸弹、后门和僵尸程序。后者由一个程序片断或者一个独立的程序构成,当其运行后,可能产生一个或者多个它本身的副本,这些副本将在同一系统或其余系统中被激活,例如病毒和蠕虫。
比较而言,恶意软件多是无害的,或者表现为一个或多个有害的操做,这些有害的操做包括毁坏内存里的文件和数据,经过绕开控制而得到权限访问和为入侵者提供一种绕开访问控制的方法。
3.6.2 对抗措施
入侵检测
RFC2828(网络安全术语表)对入侵检测的定义以下:入侵检测是一种安全服务,经过监控和分析系统事件发现试图经过未经受权的方法访问系统资源的操做,并对这种操做提供实时或者准实时的警告。
入侵检测系统(IDS)能够分为以下几类:
基于宿主的IDS:对于可疑活动,监控单个宿主的特征和发生在宿主上的事件。
基于网络的IDS:监控特定的网络段或者设备网络流量,分析网络、传输和应用协议来辨别可疑活动。
IDS 由三个部分组成:
感应器:感应器负责收集数据。感应器的输入多是系统的任一部分,输入可能包含了侵扰的证据。典型的感应器输入包括网络包、日志文件和系统调用记录。感应器收集这些信息,并把这些信息发送给分析器。
分析器:分析器从一个或多个感应器或者其余分析器接受输入数据。分析器负责肯定入侵是否发生。这部分的输出代表了一个入侵已经发生。输出可能包含了支持入侵发生的结论的证据。分析器可能提供对于入侵结果采起何种操做的指导。
用户界面:IDS 的用户界面可让用户查看系统的输出和控制系统的行为。在一些系统中,用户界面能够等同于负责人、控制器或者控制台部分。
入侵检测系统用来侦测人类入侵者行为,以及恶意软件的行为。
认证
在许多计算机安全内容中,用户认证是一个主要的构建模块和最初防线。用户认证是许多种访问控制和用户责任的主要部分。RFC2828 对用户认证作了以下定义:
系统实体定义了验证和确认的过程。认证过程包括如下两步:
确认步骤:对于安全系统,提出了标识符。(应当心地分配标识符,对于访问控制服务等其余安全服务,认证定义是基本部分。)
验证步骤:提出或产生认证信息,用来证明在实体与标识符之间的绑定。
例如,用户Alice Toklas 拥有一个用户标识符ABTOKLAS。标识符信息可能被存储在Alice想要使用的任意一台服务器或者计算机系统中,并且系统管理员和其余用户可能知道这些信息。一种典型的与用户ID 相关联的认证信息项就是密码,密码是用于保守秘密的(秘密仅仅被Alice和系统所知)。若是没有人获得或猜出Alice 的密码,管理员能够经过Alice 的用户ID 和密码的结合创建Alice 的访问许可,并审核Alice 的操做。因为Alice 的ID 不是秘密,系统用户能够给她发送电子邮件,可是因为她的密码是保密的,因此没有人能够冒充成Alice。
本质上,识别是这样一种方法:用户向系统提供一个声明的身份;用户认证就是确认声明的合法性的方法。
一共有4 种主要的认证用户身份的方法,它们既能够单独使用,也能够联合使用:
我的知道的一些事物:例如包括密码、我的身份号码(PIN)或者是预先安排的一套问题的答案。
我的拥有的一些事物:例如包括电子通行卡、智能卡、物理钥匙。这种类型的身份验证称为令牌。
我的自身的事物(静态生物识别技术):例如包括指纹、虹膜和人脸的识别。
我的要作的事物(动态生物识别技术):例如包括语音模式、笔迹特征和输入节奏的识别。
适当的实现和使用全部的这些方法,能够提供可靠的用户认证。可是每一个方法都有问题,使得对手可以猜想或盗取密码。相似地,用户可以伪造或盗取令牌。用户可能忘记密码或丢失令牌。并且,对于管理系统上的密码、令牌信息和保护系统上的这些信息,还存在显著的管理开销。对于生物识别技术,也有各类各样的问题,包括误报和假否认、用户接受程度、费用和便利与否。
访问控制
访问控制实现了一种安全策略:指定谁或何物(例如进程的状况)可能有权使用特定的系统资源和在每一个场景下被容许的访问类型。
访问控制机制调节了用户(或是表明用户执行的进程)与系统资源之间的关系,系统资源包括应用程序、操做系统、防火墙、路由器、文件和数据库。系统首先要对寻求访问的用户进行认证。一般,认证功能彻底决定了用户是否被容许访问系统。而后访问控制功能决定了是否容许用户的特定访问要求。安全管理员维护着一个受权数据库,对于容许用户对何种资源采用什么样的访问方式,受权数据库作了详细说明。访问控制功能参考这个数据库来决定是否准予访问。审核功能监控和记录了用户对于系统资源的访问。
防火墙
对于保护本地系统或系统网络免于基于网络的安全威胁,防火墙是一种有效的手段,而且防火墙同时提供了通过广域网和互联网对外部网络的访问。传统上,防火墙是一种专用计算机,是计算机与外部网络的接口;防火墙内部创建了特殊的安全预防措施用以保护网络中计算机上的敏感文件。其被用于服务外部网络,尤为是互联网、链接和拨号线路。使用硬件或软件来实现,而且与单一的工做站或者PC 链接的我的防火墙也很常见。
[BELL94]列举了以下防火墙的设计目标:
1)从内部到外部的通讯必须经过防火墙,反之亦然。经过对除通过防火墙以外本地网络的全部访问都进行物理阻塞来达到目的。能够对其进行各类各样的配置,将在本章的后面部分进行阐述。
2)仅仅容许本地安全策略定义的受权通讯经过。使用的不一样类型防火墙是经过不一样类型的安全策略实现的。
3)防火墙自己对于渗透是免疫的。这意味着在一个安全的操做系统上使用强固系统。值得信赖的计算机系统适合用做防火墙,而且在管理应用中也被要求使用。
3.7 UNIX SVR4 进程管理
UNIX 系统V 使用了一种简单可是功能强大的进程机制,且对用户可见。UNIX 采用图3.15b 中的模型,其中大部分操做系统在用户进程环境中执行。UNIX 使用两类进程,即系统进程和用户进程。系统进程在内核态下运行,执行操做系统代码以实现管理功能和内部处理,如内存空间的分配和进程交换;用户进程在用户态下运行以执行用户程序和实用程序,在内核态下运行以执行属于内核的指令。当产生异常(错误)或发生中断或用户进程发出系统调用时,用户进程可进入内核态。
3.7.1 进程状态
UNIX 操做系统中共有9 种进程状态,如表3.9 所示。图3.17(基于[BACH86]中的图)是相应的状态转换图,它与图3.9b 相似,有两个UNIX 睡眠状态对应于图3.9b 中的两个阻塞状态,其区别可简单归纳以下:
UNIX 采用两个运行态表示进程在用户态下执行仍是在内核态下执行。
UNIX 区份内存中就绪态和被抢占态这两个状态。从本质上看,它们是同一个状态,如图中它们之间的虚线所示,之因此区分这两个状态是为了强调进入被抢占状态的方式。当一个进程正在内核态下运行时(系统调用、时钟中断或I/O 中断的结果),内核已经完成了其任务并准备把控制权返回给用户程序时,就可能会出现抢占的时机。这时,内核可能决定抢占当前进程,支持另外一个已经就绪并具备较高优先级的进程。在这种状况下,当前进程转换到被抢占态,可是为了分派处理,处于被抢占态的进程和处于内存中就绪态的进程构成了一条队列。
![]() |
图3.17 UNIX 进程状态转换图 |
只有当进程准备从内核态移到用户态时才可能发生抢占,进程在内核态下运行时是不会被抢占的,这使得UNIX 不适用于实时处理。有关实时处理需求的讨论请参见第10 章。
UNIX 中有两个独特的进程。进程0 是一个特殊的进程,是在系统启动时建立的。实际上,这是预约义的一个数据结构,在启动时刻被加载,是交换进程。此外,进程0 产生进程1,称作初始进程,进程1 是系统中的全部其余进程的祖先。当新的交互用户登陆到系统时,由进程1为该用户建立一个用户进程。随后,用户进程能够建立子进程,从而构成一棵分支树,所以,任何应用程序都是由一组相关进程组成的。
表3.9 UNIX 进程状态
![]() |
3.7.2 进程描述
UNIX 中的进程是一组至关复杂的数据结构,它给操做系统提供管理进程和分派进程所须要的全部信息。表3.10 归纳了进程映像中的元素,它们被组织成三部分:用户上下文、寄存器上下文和系统级上下文。
表3.10 UNIX 进程映像
![]() |
用户级上下文包括用户程序的基本成分,能够由已编译的目标文件直接产生。用户程序被分红正文和数据两个区域,正文区是只读的,用于保存程序指令。当进程正在执行时,处理器使用用户栈进行过程调用和返回以及参数传递。共享内存区是与其余进程共享的数据区域,它只有一个物理副本,可是经过使用虚拟内存,对每一个共享进程来讲,共享内存区看上去好像在它们各自的地址空间中同样。当进程没有运行时,处理器状态信息保存在寄存器上下文中。
系统级上下文包含操做系统管理进程所须要的其他信息,它由静态部分和动态部分组成,静态部分的大小是固定的,贯穿于进程的生命周期;动态部分在进程的生命周期中大小可变。静态部分的一个成分是进程表项,这其实是由操做系统维护的进程表的一部分,每一个进程对应于表中的一项。进程表项包含对内核来讲老是能够访问到的进程控制信息。所以,在虚拟内存系统中,全部的进程表项都在内存中,表3.11 中列出了进程表项的内容。用户区,即U 区,包含内核在进程的上下文环境中执行时所须要的额外的进程控制信息,当进程调入或调出内存时也会用到它。表3.12 给出了这个表的内容。
表3.11 UNIX 进程表项
![]() |
(续)
![]() |
表3.12 UNIX 的U 区
![]() |
进程表项和U 区的区别反映出UNIX 内核老是在某些进程的上下文环境中执行,大多数时候,内核都在处理与该进程相关的部分,可是,某些时候,如当内核正在执行一个调度算法,准备分派另外一个进程时,它须要访问其余进程的相关信息。当给定进程不是当前进程时,能够访问进程控制表中的信息。
系统级上下文静态部分的第三项是本进程区表,它由内存管理系统使用。最后,内核栈是系统级上下文环境的动态部分,当进程正在内核态下执行时须要使用这个栈,它包含当发生过程调用或中断时必须保存和恢复的信息。
3.7.3 进程控制
UNIX 中的进程建立是经过内核系统调用fork()实现的。当一个进程产生一个fork 请求时,操做系统执行如下功能[BACH86]:
1)为新进程在进程表中分配一个空项。
2)为子进程赋一个惟一的进程标识符。
3)作一个父进程上下文的逻辑副本,不包括共享内存区。
4)增长父进程拥有的全部文件的计数器,以表示有一个另外的进程如今也拥有这些文件。
5)把子进程置为就绪态。
6)向父进程返回子进程的进程号;对子进程返回零。
全部这些操做都在父进程的内核态下完成。为当内核完成这些功能后能够继续下面三种操做之一,它们能够认为是分派器例程的一个部分:
在父进程中继续执行。控制返回用户态下父进程进行fork 调用处。
处理器控制权交给子进程。子进程开始执行代码,执行点与父进程相同,也就是说在fork调用的返回处。
控制转交给另外一个进程。父进程和子进程都置于就绪状态。
很难想象这种建立进程的方法中父进程和子进程都执行相同的代码。其区别在于:当从fork中返回时,测试返回参数,若是值为零,则它是子进程,能够转移到相应的用户程序中继续执行;若是值不为零,则它是父进程,继续执行主程序。
3.8 小结
现代操做系统中最基本的构件是进程,操做系统的基本功能是建立、管理和终止进程。当进程处于活跃状态时,操做系统必须设法使每一个进程都分配处处理器执行时间,并协调它们的活动、管理有冲突的请求、给进程分配系统资源。
为执行进程管理功能,操做系统维护着对每一个进程的描述,或者称为进程映像,它包括执行进程的地址空间和一个进程控制块。进程控制块含有操做系统管理进程所须要的全部信息,包括它的当前状态、分配给它的资源、优先级和其余相关数据。
在整个生命周期中,进程老是在一些状态之间转换。最重要的状态有就绪态、运行态和阻塞态。一个就绪态进程是指当前没有执行但已作好了执行准备的进程,只要操做系统调度到它就当即能够执行;运行态进程是指当前正在被处理器执行的进程,在多处理器系统中,会有多个进程处于这种状态;阻塞态进程正在等待某一事件的完成,如一次I/O 操做。
一个正在运行的进程可被一个在进程外发生且被处理器识别的中断事件打断,或者被执行操做系统的系统调用打断。不论哪一种状况,处理器都执行一次模式切换,把控制转交给操做系统例程。操做系统在完成必需的操做后,能够恢复被中断的进程或者切换到别的进程。