现代操作系统(二)

磁盘

主存的再下一层次就是磁盘(硬盘)

它最慢,比我们的主存慢了三个数量级,而慢的主要原因是因为它是一种机械装置

磁盘中的每一个盘片都在高速的旋转

每个盘面一个读写头(磁头),每个磁头可以读一段环形区域,称为磁道。

把给定臂的所有磁道合并起来,形成一个柱面,这个柱面可以移动,机械臂从一个柱面移到另一个柱面1ms,还要等到扇区旋转至磁头下,有要5-10ms,所以造成了延迟

固态硬盘并不是磁盘,它没有移动的部分,数据只是存在存储器(闪存)中

许多计算机支持虚拟内存机制(以后会讲到),这种机制使得期望运行大于物理内存的程序成为可能,这种机制由CPU中的存储器管理单元(MMU)来完成

如图

cpu


缓存和MMU的出现对系统的性能有着重要影响,对来自缓存中的块写回磁盘并修改MMU中的寄存器的代价非常昂贵,程序员努力避免这些操作,后面会看到这些操作所产生的影响

I/O设备


cpu和存储器并不是操作系统唯一管理的资源,I/O设备也有着密切的相互影响

它包括设备控制器和设备本身

控制器为操作系统提供一个接口(这些极其复杂)

比如磁盘控制器,它接收到指令,读取磁盘2,某扇区。接着就是柱面的移动等一系列机械操作

所以控制器中通常安装一个小的嵌入式计算机,运行为执行这些工作的程序

设备的自身也有一个简单的接口,这些接口都通常都被标准化的,例如现在的SATA是很多计算机的标准硬盘接口

注意,操作系统看到的是控制器的接口,这个接口可能和设备接口有很大区别

每类设备控制器都是不同的,所以需要不同的软件进行控制,专门与控制器对话

而这些软件就是 设备驱动程序(device driver)

每个控制器厂家必须为不同的操作系统提供相应的设备驱动程序

如一台打印机有windows7、windows8、linux的设备驱动程序

要运行设备驱动程序,需要安装到操作系统中,它可在内核态下运行,用户态也可,只不过后者要求较高

将设备驱动程序装入操作系统有三个途径

一 将内核与设备驱动程序重新链接,然后重启

二 在操作系统文件中设置一个入口,告知该文件需要一个设备驱动程序

三 运行时接受新的驱动程序并安装好,无需重新启动系统,比如USB

每个控制器都会有少量用于通讯的寄存器,比如磁盘控制器中,有用于指定磁盘地址、内存地址、扇区计数的寄存器

要激活控制器,设备驱动程序需要从操作系统中获得指令,并写入寄存器中,这些寄存器所组成的集合构成了I/O端口空间(我们将会从后面讲到)

在有些计算机中,这些寄存器的地址空间被映射到了操作系统的地址空间,这一就可以像普通存储字一样读出和写入,在这样的计算机中不需要专门的I/O指令,但占用了地址空间

另外一些计算机设备存储器被放进一个专门的I/O端口空间中,每个寄存器都有一个端口地址,这种不需要占用地址空间,但需要专门的I/O指令

实现输入输出的方法有三种

一 用户程序发出一个系统调用,操作系统翻译成一个对应设备驱动程序的过程调用,该设备驱动程序把数据送到指定的地方并返回,然后操作系统将控制返回给调用者,这种称为忙等待 占用cpu

二 设备驱动程序启动设备并且该设备操作完成时,发出一个中断,并通知操作完成

在操作系统中,中断非常重要,需要更细致的讨论


这个图有一个关于I/O设备的三步过程

1 驱动程序告知控制器,控制器启动设备

2 向中断芯片发出中断信号

3 如果芯片接收中断信号(看是否有更高级的中断)

4 中断控制器把该设备放回总线上,cpu可以继续总线,并知道哪个设备完成了操作

当cpu决定中断时,程序计数器和PSW被压入堆栈种,设备编号成为了部分内存的引用,用于寻找中断处理程序的地址,该部分内存称为中断向量

当中断处理程序开始后,它取走入栈的值并保存,然后查询设备状态。中断处理程序全部完成后它返回到用户尚未执行的头一条指令

三 为I/O使用一种特殊的 直接存储器访问芯片(DMA) 这种芯片由cpu设置,接着启动DMA,当完成工作后会发出一个中断

总线


图中的系统有很多总线,高速缓存、内存、PCIe、USB、STAT、DMI等总线


随着处理器越来越快,单总线已不能满足需求

操作系统必须了解所有的总线与配置

其中最主要的总线是PCIe总线

它取代了旧的PCI、ISA总线,它的好处是像网络报一样,所有数据不需同时到达

USB是用来给慢速设备连接电脑的,如键盘、鼠标等

USB1.0只 12m/s  usb2.0 480m/s  usb3.0  5Gb/s

如果想运行类似于图片的计算机,必须让操作系统知道哪些设备连接到了计算机上并配置他们

以前的连接一个设备,设备的寄存器有一个中断级别和固定地址

这就导致有可能两个中断级别相同的设备不能同时连接到计算机上

所以就有了即插即用的I/O系统,它主要是自动分配中断级别和地址

它与计算机启动密切相关

启动计算机

计算机的双亲板(母版)上有一个BIOS配置程序,它存在一块闪存RAM中

启动时,BIOS开始运行,他首先会检查所安装的RAM数量,并检查键盘等设备是否已安装,检查对应的设备驱动程序是否存在,若不存在,会被要求下载

接着,他开始扫描总线,若有新的则会被配置

等全部设备驱动程序加载完后,操作系统将他们调入内核

然后,初始化表格,创建相关进程

最后启动登录程序或界面

如果存在CD-ROM(有时是USB),系统会试图从中启动,若失败,系统将从硬盘启动

操作系统已存在了半多个世纪

其中出现了很多操作系统,我们将介绍比较出名的9个,再进入操作系统的概念

1大型机操作系统

2服务器操作系统

3多处理器操作系统

4个人计算机操作系统

5掌上计算机操作系统

6嵌入式操作系统

7传感器节点操作系统

8实时操作系统

9智能卡操作系统

操作系统概念(这里只是简单介绍,后面会详细讨论)

进程

本质是一个正在执行的程序,与之相关的是地址空间、资源集(寄存器)、进程的清单,及所有与之运行所需要的全部信息

进程基本是容纳着这个程序运行所需的信息的容器

一个进程被挂起后,再次启动时必须与之前的状态要一模一样

所以在操作系统中有一个进程表,记录着除程序自身的地址空间外的所有信息

所以一个挂起的进程包括自己的地址空间(也称磁芯映像),和与之对应的,在操作系统上的进程表

若一个进程,又创建了一个进程,则这个进程称为子进程,如果一直创建下去就会变为进程树


比如我们运行着编译工具,此时再键入一个命名,编译一个程序

编译工具必须创建一个新进程来执行编译程序

当编译完成后,执行编译程序的进程会执行一个系统调用来终止自己

系统管理器会授予每个进程一个UID,子进程与父进程拥有一个UID,UID中又有一个GID,GID相当于windows中的管理员,linux中的超级用户

地址空间

每台计算机都有一个主存,用来保存正在执行的程序。

所以一个进程可拥有的最大地址空间小于主存

所以进程可以用满主存,主存也可容纳该进程

那么进程的地址空间大于主存怎么办?

在以前,可能只能认命了

但现在,出现了正如前面所说的,虚拟内存技术,把地址空间的一部分装在主存一部分装在磁盘,需要时来回调用他们

文件

操作系统的主要职责隐蔽磁盘及I/O设备的细节特性,从而给程序员提供一个抽象的模型

文件就是很好的例子

大多操作系统都支持目录的概念,就是给文件分组和分类,目录项可以是文件或者目录

这样就产生了层次结构,构成文件系统


进程和文件都是树的结构,但进程很少超过三层,而文件一般三层以上,且存在的时间也比进程长久得多

从根目录开始往下延展的称为绝对路径,没有根目录的称为相对路径

每个进程都有一个工作目录,如果不是绝对路径,则从当下工作目录寻找

在unix系统中,有一种特殊文件,块特殊文件和字符特殊文件

管道(pip)


管道是一种虚文件,与文件有关,也与进程有关

它可以连接两个进程,如果进程A与进程B希望通过管道对话,必须要提前设置该管道

A想发送信息给B,就在管道上写入,B只要读取就行了

输入/输出

键盘、显示器、打印机这些全靠操作系统来管理

所以,每个操作系统都有一个管理这些设备的子系统(I/O子系统),与之对应的I/O软件

保护

比如linux上的 rwx位 对文件进行保护

shell

是用户和操作系统交互的接口

我们常见的windows界面,但他不是操作系统的一部分

系统调用

前面说过, 操作系统具有两种功能,提供抽象和管理资源

对用户来说,他们只能看到前者,比如创建、写入、删除文件

而后者是自动且透明的

想要真正理解操作系统的行为,必须仔细的分析这些接口

任何单cpu计算机一次只能执行一条命令

当用户正在运行一个用户程序时,突然需要一个服务,比如文件读取数据,那么它必须执行一个陷阱或系统调用,将控制移交给操作系统,操作系统找出所需要的调用过程,执行他然后返回给这个用户程序后面跟随的指令

比如提供 过程库 使c程序能够使用系统调用

如read调用

count = read(fd,buffer,nbytes);


第一,二,三步,把程序压入堆栈中

第四步,对库过程的实际调用

第五步,放在寄存器中

第六步,执行一个TRAP指令,将用户态切换到内核态,并在一个指定块里执行

第七步,分派正确的系统调用处理器

第八步,系统调用处理器运行

第九步,返回给用户空间库过程

第十步,返回到用户程序

接下来我们将讨论一下POSIX(international standard 9945-1)

他大概有100个过程调用

主要分为4类

1.进程管理、2.文件管理、3.目录和文件系统管理、4.杂项

1.用于进程管理的系统调用


在shell中执行一个命令,shell调用了fork创建了一个新进程(子进程)

这个子进程必须执行用户的命令

在cp file1 file2中

cp主程序都有声明 main(argc,argv,envp)

argc是该命令行有关参数的数目,包括cp的名称,如在cp file1 file2中argc为3

argv是一个指向数组的指针,argv[o],argv[1],argv[2]分别指向cp file1 file2

envp是指向环境的指针,在cp这个例子中的环境变量为数组,fork中没有环境变量

UNIX中将进程分为三段


堆栈向下增长

数据向上增长

夹在中间的是未使用的地址空间

2.用于文件管理的系统调用


lseek,是一个文件当前的指针

它有三个参数,第一个文件的描述符,第二个文件的位置,第三个说明文件是相对于文件起始位置、当前位置还是结尾

3.用于目录管理的系统调用


这里有注意的是link 是允许同一个文件以两个或多个名称出现

link("/usr/jim/memo","usr/ast/note")

jim目录中的文件memo以文件名note进入了sat目录中


其本质就是i-编号对i-节点表格的一个引用,因为我们的文件是(i-编号,ASCII名称)的结构

mount可以将usb文件系统添加到根文件系统中


4.各种系统调用


Windows Win32 API(Win32应用编程系统)

前面我们主要讨论的是UNIX系统

接下来我们将讨论windows

UNIX与windows的主要区别在于,前者是通过代码做各种处理,而后者是事件驱动型,就是主程序等待响应,比如敲键盘等

在UNIX中系统调用(read)和系统调用所使用的库过程(read)是一一对应的,换句话说就是,每启动一个系统调用,就要启动一个对应的库过程,POSIX大约有100个

在windows中就不一样了,库调用和实际的调用几乎不对应

win 32API 给用户提供了这个接口,他大概有1000多个,且大部分都是在用户空间的库调用,他们不陷入内核


在window中没有子进程和父进程的概念,他们被创建后是平等的

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容