Linux系统大致可分为三层: 靠近硬件的底层是内核,即Linux操作系统常驻内存部分。 中间层是shell层,即操作系统的系统程序部分。 最高层是应用层,即用户程序部分 内核是Linux操作系统的主要部分,实现进程管理、内存管理、文件系统、设备驱动和网络系统等功能。 Linux操作系统的心脏-内核 区分用户态和内核态目的在于安全考虑: 1.禁止用户程序和底层硬件直接打交道 最简单的例子,如果用户程序往硬件控制寄存器写入不恰当的值,可能导致硬件无法正常工作 2.禁止用户程序访问任意的物理内存 否则可能会破坏其他程序的正常执行,如果对内核所在的地址空间写入数据的话,会导致系统崩溃 用户程序如何同设备打交道? 例如,用户需通过网卡发送数据 1.硬件被linux 内核隔离,只能通过内核实现。 2.不可能直接调用操作系统的函数:不可行,也不安全。 Linux提供的解决方法:系统调用 系统调用的意义: 操作系统为用户态进程与硬件设备进行交互提供了一组接口——系统调用 1.把用户从底层的硬件编程中解放出来 2.极大的提高了系统的安全性 3.使用户程序具有可移植性 内核的核心-进程 Fork()——创建新进程 ,是父进程的一个克隆 父-子-孙共存的系统必然是一个并发的系统 2 进 程 管 理 1.进程及其状态 简单说来,进程就是程序的一次执行过程 进程至少要有三种基本状态: 运行态、就绪态和封锁态(或等待态) 进程的状态可依据一定的条件和原因而变化 在Linux系统中,进程的模式划分为用户模式和内核模式; 按照进程的功能和运行的程序来分,进程划分为两大类: 系统进程、用户进程 用户进程可以在用户模式和内核 模式下运行 系统进程只运行在内核模式 若当前运行的是用户程序、应用程序或者内核之外的系统程序,则在用户模式下运行。 在用户程序执行过程中,如果使用了系统调用,或者发生了中断,就要运行操作系统程序,进程模式变为内核模式。 2.Linux线程 线程和进程是紧密相关的概念 一般来说,Linux系统中的进程应具有: 一段可执行的程序、 专用的系统堆栈空间、 私有的“进程控制块”、 独立的存储空间 而Linux系统中,线程只具有前3个组成部分, 缺少自己的存储空间 进程的结构: Linux系统中的每个进程都有一个名为task_struct的数据结构,它相当于“进程控制块”; 在进程被创建时,系统从内存中分配一个task_struct的数据结构。 包含下列几方面的信息: 进程状态 调度信息 标志符 内部进程通讯 链接信息 时间和计时器 文件系统 虚拟内存 处理器信息 进程系统堆栈 每个进程都有一个系统堆栈,用来保存中断现场信息,以及进程进入内核模式后的返回现场信息; 系统堆栈和task_struct数据结构之间存在紧密联系,二者物理存储空间也连在一起 系统堆栈的大小静态确定 对进程的操作: 1.进程的创建 各个进程构成了树形的进程族系 内核在完成了基本的初始化以后,就有了系统的第一个进程 所有其他的进程和内核线程都由这个原始进程或其子孙进程所创建。 2.进程的等待 父进程创建子进程,往往是让子进程替自己完成某项工作,因此,创建之后,父进程通常需要等待子进程运行结束; 父进程可用系统调用wait( )等待它的子进程终止; 3.进程的终止 进程可使用系统调用exit( )终止自己; 其实现算法如下: (1)撤消所有的信号量。 (2)释放其所有的资源,包括存储空间、已打开的文件、工作目录、信号处理表等。 (3)置进程状态为“终止态”(TASK_ZOMBIE)。 (4)向它的父进程发送子进程终止的信号。 (5)执行进程调度。 4.进程调度 进程调度-系统有条不紊的使者 调度算法 调度时机 进程切换 任何程序要占用CPU,真正处于执行状态,就必须经由进程调度 进程调度机制要兼顾以下三种不同进程的需要 1.交互进程:需要经常响应用户操作,着重于系统的响应速度,使得共有一个系统的各个用户,都感到自己在独占系统,典型的交互程序有shell,文本编辑器; 2.批处理进程:也称作“后台作业”,在后台运行,对响应速度无要求,只考虑“平均速度”,如:编译程序、科学计算等; 3.实时进程:对时间有很高要求,不仅考虑平均速度,还对完成任务的时间限制有要求。 1.调度方式 Linux内核的调度方式,基本上采用“抢占式优先级”, 当进程在用户模式下运行时,在一定条件下(如:时间片用完),内核调度其他进程进入运行; 在选择其他进程时以优先级为基础 1.系统中的每个进程都有个优先权,反映了该进程可以获得CPU使用权的资格; 2.从进程就绪队列中选择一个优先权最高的进程,为其分配一个CPU时间片; 3.运行过程中,当前进程的优先级随时间递减,从而经过一段时间后,以前优先级较低的进程就相对“提升”了优先级,有机会运行; 4.当所有进程优先级都变为0时,就重新计算一次优先级。 调度策略——三种不同的调度策略 SCHED_FIFO 适合于短实时进程, 对时间性要求比较强,每次运行所需时间较短 SCHED_RR 适合于运行时间较长的实时进程,也叫“时间片轮转法” 。 当时间片用完时,该进程被送回相同优先级队列的末尾, 因此,进程从创建到完成需要经过多次循环调用; SCHED_OTHER 适合于交互式的分时进程,这类进程的优先权取决于两个因素: 1、进程剩余时间配额:若已经用完配给的时间,则优先权为0 2、进程的优先数:沿袭UNIX的方法 3.调度的时机 当前进程使用系统调用,使自己进入睡眠状态,主动让出一段时间的CPU使用权。 进程终止,永久地放弃对CPU的使用。 当唤醒一个睡眠进程时,发现被唤醒的进程比当前进程更有资格运行。 一个进程通过执行系统调用,来改变调度策略或者降低自身的优先权,从而引起立即调度。 4.调度算法 调度算法比较简单,以便减少频繁调度时的系统开销。 首先查找所有就绪队列中的进程,选出优先级最高、且在内存的一个进程; 如果队列中有实时进程,那么将优先运行; 如果需要运行的进程不是当前进程,那么当前进程就被挂起,并且保存它的现场, 然后为选中的进程恢复其运行现场; shell基本工作原理 Linux系统提供给用户的最重要的系统程序是shell命令, 它不属于内核部分,基本功能是解释并执行用户输入的各种命令,实现用户与Linux内核的接口。 系统初次启动后,系统为每个终端用户建立一个进程,以执行shell解释程序。 文 件 系 统 Linux系统的一个重要特征,就是支持多种不同的文件系统, 如:ext, FAT, ext2, ext3, MINIX, MS DOS, SYSV等。 目前,Linux主要使用的文件系统是ext3 ext3是ext2的升级版本,其主要优点是: 在ext2的基础上加入了记录数据的日志功能 1 ext2文件系统 与其他文件系统一样,文件信息都保存在数据块中, 所有数据块的大小都是一样的 介质上的第一个数据块,只有根文件系统才有引导程序 块组的构造 包含超级块、组描述结构、块位图、索引节点位图、索引节点表和数据块。 1)超级块(Superblock) 超级块中包含有文件系统本身的大小和形式的基本信息 例如: 块组号码 、数据块大小 、每组数据块的个数、空闲块 、空闲索引节点 、第一个索引节点 2)块组描述结构(Block Group Descriptor) 每个数据块组都有一个描述它的数据结构,即块组描述结构。 3)索引节点(Inode) 每个文件都有惟一一个索引节点,起着文件控制块的作用 利用这种数据结构可对文件进行控制和管理。 索引节点有两种形式:盘索引节点、内存索引节点 4)多重索引结构 如果文件索引表很大,则把索引表整个放在内存中是不合适的,在使用过程中很可能需要扩充空间; 此外,单一索引表已经无法满足灵活性和节省内存的要求; 为此,提出多重索引结构,采用间接索引的方式,进行几级寻址,最末尾的数据块中存储文件具体内容; 文件系统在查找文件时,根据路径名和文件名,搜索对应的索引节点,找到该文件的数据块; ext2中的目录项 当创建一个文件时,就构成一个目录项,并添加到相应的目录文件中 一个目录文件可以包含很多目录项,每个目录项包含的信息有: 索引节点号 目录项长度 名字长度 文件类型 文件名字 例如:要读取文件/home/meng/m1.c 1.文件系统首先按照超级块中根目录的索引节点, 找到根目录的数据块,从中找到表示home文件的目录项,得到相应索引节点的号码; 2.接着在节点中找到存放home数据块的地址,从中找到meng对应的目录项, 得到相应的索引节点号码; 3.再由meng目录文件中获取m1.c文件的索引节点号码,通过这个节点就可以访问m1.c文件。 Linux系统中每个进程控制块都有两个数据结构,用来描述进程与文件相关信息。 files_struct保存该进程打开文件的有关信息。最多打开256个文件 每个块组中包含一个块位示图,和一个索引节点位示图 位示图管理块组的数据块,具体方法是: 利用一串二进位的值来反映该块组中数据块的分配情况 也称作位向量(Bit Vector)法。 0表示空闲,1表示已分配 2 虚拟文件系统 Linux系统可以支持多种文件系统,为此,必须使用一种统一的接口, 这就是虚拟文件系统VFS(Virtual File System). VFS是一个软件层,是用户应用程序与具体文件系统实现之间的抽象层: 对用户界面: 一组标准的、抽象的文件操作,以系统调用提供 如read()、write()、open()等 对具体文件系统界面 主体是file_operations结构,全是函数指针,提供函数跳转表。 VFS在一个简单文件复制操作中的作用: 假设用户输入shell命令:$ cp /floppy/TEST /tmp/test 在cp命令中,通过VFS提供的系统调用接口进行文件操作。 inf=open("/floppy/TEST",O_RDONLY,0); outf=open("/tmp/test",O_WRONLY|O_CREAT|O_TRUNC,0600); do{ i=read(inf,buf,4096); write(outf,buf,i); }while(i); close(outf); close(inf); VFS支持的文件系统类型 基于磁盘的文件系统: 管理在本地磁盘分区中可用的存储空间。 网络文件系统: 用于访问属于其他网络计算机的文件系统所包含的文件 特殊文件系统 文件系统的安装与拆卸: 在系统初启时,往往只有一个文件系统安装上,即:根文件系统,主要包括 保证系统正常运行的操作系统代码文件,以及语言编译程序、命令解释程序、命令处理程序、以及用户文件; 根文件系统一旦安装上,则在整个系统运行过程中是不能卸载的; 其他的文件系统(例如,由软盘构成的文件系统),可以根据需要(如从硬盘向软盘复制文件),作为子系统动态地安装到主系统 VFS有下列主要对象类型: 超级块对象(superblock ) 存放文件系统相关信息:例如文件系统控制块 索引节点对象(inode ) 存放具体文件的一般信息:文件控制块/inode 目录项对象(dentry ) 存放目录项与文件的链接信息 文件对象(file ) 存放已打开的文件和进程之间交互的信息 VFS索引节点缓存和目录缓存 为了加快对系统中所有已经安装文件系统的存取,VFS提供了索引节点缓存——把当前使用的索引节点保存在高速缓存中。 为了能够很快地从中找到所需的VFS索引节点,采用散列(hash)方法 数据块缓冲区 Linux系统采用多重缓冲技术,来平滑和加快文件信息从内存到磁盘的传输; 一个缓冲区由两部分组成:存放数据的缓冲区和一个缓冲控制块; 所有处于“空闲”状态的buffer_head 都链入自由链中,它只有一条。 具有相同散列值的缓冲区组成一条散列队列. 内 存 管 理 Linux系统采用了虚拟内存管理机制,就是交换和请求分页存储管理技术: 地址映射机制 请页机制 内存分配和回收机制 交换机制 缓存和刷新机制 物理内存有限,是一种稀缺资源 32位系统中,每个进程独立的占有4G虚拟空间 虚拟内存优势: 用户程序开发方便 保护内核不受恶意或者无意的破坏 隔离各个用户进程 物理内存获取过程: 用户程序请求物理内存 内核分配物理页面 内核填写对应页表项 用户程序获得物理内存 内存管理的核心内容是 物理内存管理 和 虚拟空间管理 1 请求分页机制 分页的概念 逻辑空间分页:进程的逻辑地址空间划分为大小相等的页面 内存空间分页:内存也划分成相同大小的存储块; 逻辑地址表示:地址结构如图所示 内存分配原则:以内存块为单位分给进程,并且进程的页面可以装在物理上不连续的内存块中 页表:由于页号连续,而块号不一定连续,为了找到进程的每个页面对应内存中的物理块号,为每个进程建立页表。 Linux的多级页表 每个进程的虚拟存储空间可达4GB,分为两个部分: 系统空间1G + 用户空间3G Linux系统中页面大小为4K,因此,进程的虚存空间要划分为4G/4K=220个页面 内存页的分配与释放 Linux系统采用两种方法来管理内存页 位图:记录内存单元的使用情况 链表:记录已分配的内存单元和空闲的内存单元 采用双向链表结构将内存单元连接起来,可以加速空闲内存的查找,或链表处理操作。 进 程 通 信 系统中的进程与内核之间,以及不同的进程之间,需要进行通信和协调,最常用的通信方式是: 信号机制 管道文件 System V IPC(内部进程通信)机制 1.信号概念 信号(signal,称为软中断)机制:是在软件层次上对中断机制的一种模拟。 异步进程可以通过彼此发送信号来实现简单通信。 1.接收信号的进程,在运行过程中检测自身是否收到信号; 2.若收到信号,则转去执行预先规定好的信号处理程序; 3.再返回原先正在执行的进程 除了内核和超级用户之外,并不是每个进程都可以向其他进程发送信号;普通进程只能向具有相同uid和gid的进程发送信号。 2 管道文件 $grep m?.c | wc –l 执行上述命令时,就要创建一个管道文件,和两个进程 1.命令grep m?.c对应一个进程,向管道文件中写入信息,称为“写进程”; 2.命令wc –l对应另一个进程,从管道文件中读取信息,称为“读进程” 由系统自动处理上述两个进程间的同步、调度和缓冲。 管道文件允许两个进程按先入先出(FIFO)的方式传送数据