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)的方式传送数据