ARM9嵌入式系统设计——基于S3C2410与Linux_P296-301
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Linux内核的结构
操作系统内核的结构模式可分为两种:整体式的单内核模式和层次式的微内核模式。
1.单内核
单内核也叫集中式操作系统。
整个系统是一个大模块,可以被分为若干逻辑模块,即处理器管理、存储器管理、设备管理和文件管理,其模块间的交互是通过直接调用其他模块中的函数实现的。
单内核模型以提高系统执行效率为设计理念,因为整个系统是一个统一的内核,所以其内部调用效率很高。
单内核的缺点也正是由于其源代码是一个整体而造成的:通常各模块之间的界限并不特别清晰,模块间的调用比较随意,所以进行系统修改或升级时,往往“其一发而动全身”,导致工作量加大,使其难以维护。
2.微内核
微内核是指把操作系统结构中的内存管理、设备管理、文件系统等高级服务功能尽可能地从内核中分离出来,变成几个独立的非内核模块,而在内核中只保留少量最基本的功能,使内核变得简洁可靠。
微内核实现的基础的操作系统理论层面的逻辑功能划分。
几大功能模块在理论上是相互独立的,形成比较明显的界限,其优点如下:
·充分的模块化设计,可独立更换任一模块而不会影响其他模块,从而方便第三方开发、设计模块。
·未被使用的模块功能不必运行,因而能大幅度减少系统的内存需求。
·具有很高的可移植性,理论上讲只需要单独对各微内核部分进行移植修改即可。
由于微内核的体积通常很小,而且互不影响,因此工作量很小。
微内核的明显缺点是系统运行效率低,因为各个模块与微内核之间是通过通信机制进行交互的。
Linux内核主要由5个子系统组成:进程调度、内存管理、虚拟文件系统、网络接口和进程间通信。
进程调度控制进程对CPU的访问,采用适当的调度策略使各进程能够合理的使用CPU。
内存管理(MM)允许多个进程安全的共享主内存区域。
Linux的内存管理支持虚拟内存,即在计算机中运行的程序,其代码、数据和堆栈的总量可以超过实际内存的大小,操作系统只是把当前使用的程序块保留在内存中,其余的程序块则保留在磁盘中。
必要时,操作系统负责在磁盘和内存之间交换程序块。
虚拟文件系统(Virtual File System,VFS)隐藏了各种硬件的具体细节,为所有的设备提供统一的接口,从而提供并支持与其他操作系统兼容的多种文件系统格式。
网络接口(NET)提供了对各种网络标准的存取和各种网咯硬件的支持。
进程间通信(IPC)支持进程间各种通信机制。
6.2.1 进程调度
进程调度控制进程对CPU的访问。
采用适当的调度策略使各进程能够合理的使用CPU。
一般情况下,当一个进程等待硬件操作完成时,他被挂起。
当硬件操作完成时,进程恢复执
行。
例如,当一个进程通过网路发送一条消息时,网络接口需要挂起发送进程,直到硬件成功地完成消息的发送;当消息被成功地发送出去以后,网络接口给进城返回一个代码,表示操作的成功与失败。
1. 进程的定义
一个进程是程序的一次执行过程。
程序是静态的,它是一些保存在磁盘上的可执行的代码和数据集合。
进程是一个动态的概念,它是Linux系统的基本调度单位。
一个进程由如下元素组成:
·程序的读取上下文,它表示程序读取执行的状态;
·程序当前执行目录;
·程序服务的文件和目录;
·程序的访问权限;
·内存和其他分配给进程的系统资源。
Linux进程中最知名的属性就是它的进程号(Process Identity Number,PID)以其父进程号(Parent Process ID,PPID)。
PID、PPID都是非零正整数。
一个PID唯一地标识一个进程。
一个进程创建新进程称为创建了子进程(Child Process),创建子进程的进程称为父进程。
所有进程追溯其祖先最终都会落到进程号为1的进程身上,这个进程叫做init进程,是内核自举后第一个启动的进程。
Init进程的作用是扮演终结父进程的角色。
因为init进程永远不会被终止,所以系统总是确信它的存在,并在必要时以它为参照。
如果某个进程在它衍生出来的全部子进程结束之前被终止,就会出现必须以init为参照的情况。
此时那些失去了父进程的子进程就都会以init作为其父进程。
通过执行ps-af命令,可以列出许多父进程ID为1的进程。
Linux提供了一条pstree命令,允许用户查看系统内正在运行的各个进程之间的继承关系。
直接在命令行输入pstree,程序会以树状结构方式列出系统中正在运行的各进程之间的继承关系。
2. Linux进程的状态
Linux进程主要有以下几种状态。
(1)可运行状态:进程正在运行或处于就绪,只要得到CPU就可以立即投入运行的就绪态。
(2)等待状态:进程正在等待某个事件发生或等待某种资源的状态。
Linux进程有两种等待状态,即可中断的等待状态和不可中断的等待状态。
(3)暂停状态:此时进程暂时停止运行,接受某种处理。
(4)僵死状态:表示进程结束但尚未消亡的一种状态。
3. Linux进程的结构
Linux中一个进程在内存中有3部分数据区,分别是数据段、堆栈段和代码段。
代码段用来存放程序代码,假如机器中有数个进程运行相同的一个程序,那么它们就可以使用同一个代码段。
数据段用来存放程序的全局变量、常数以及动态数据分配的数据空间。
堆栈段用来存放子程序的返回地址、子程序的参数以及程序的局部变量。
堆栈段包括进程控制块PCB (Process Control Block)。
PCB处于进程核心堆栈的底部,不需要额外分配空间。
4. Linux进程的种类
Linux操作系统包括3种不同类型的进程,每种进程的特点和属性如下。
(1)交互进程:由一个shell启动的进程,既可以在前台运行,也可以在后台运行。
(2)批处理进程:不与特定的终端相关联,提交到等待队列中顺序执行进程。
(3)守护进程:在Linux启动时初始化,需要时运行于后台的一些服务进程。
5. Linux进程的创建
在Linux下创建进程的系统函数是fork()函数,这个函数名是“分叉”的意思。
Fock 函数的语法格式为:
#include <sys/types.h> /* 提供类型pid_t的定义*/
#include <unistd.h> /* 提供函数的定义*/
Pid_t fork();
调用fork函数之后,操作系统会复制一个与父进程完全相同的子进程。
虽说是父子关系,但是在操作系统看来,它们更像兄弟关系。
这两个进程共享代码空间,但是数据空间是互相独立的,子进程数据空间中的内容是父进程的完整复制,指令指针也完全相同。
两者唯一不同的是:如果fork成功,子进程中fork的返回值是0,父进程中fork的返回值是子进程的进程号;如果fork不成功,父进程会返回错误。
6. Linux进程控制块task_structd的结构描述
Linux在内核空间专门开辟了一个指针数组task,用来有效地管理所有进程控制块task_struct结构的指针。
Task数组大小限制了系统并执行的进程总数。
task_struct结构包含的信息如下。
(1)进程当前的状态。
(2)调度信息:进程的类别、调度策略、优先级等调度属性在此保存。
(3)进程标识:进程标识号PID、组标识号GID和用户标识号UID等。
(4)进程通信信息:Linux支持多种进程通信机制,task_struct结构中存储了与进程通信有关的信息。
(5)进程的家族关系:有许多进程指针,分别指向祖先进程(初始化进程)、父进程、子进程及新、老兄弟进程的task_struct结构。
(6)时间和定时信息:用于追踪和记录进程在整个生存期内使用CPU时间。
(7)文件系统信息:保存了进程与文件系统相关的信息。
(8)存储管理信息:存储了进程虚拟内存空间信息及其物理存储有关的信息。
(9)CPU现场保留信息:CPU寄存器、堆栈等环境。
进程所有操作都要依赖task_struct结构,task_struct结构是进程实体的核心,是进程存在的唯一标志。
6.2.2 内存管理
内存管理(MM)允许多个进程安全的共享主内存区域。
Linux的内存管理支持虚拟内存,即在计算机中运行的程序,其代码、数据和堆栈的总量可以超过实际内存的大小,操作系统只是把当前使用的程序块保留在内存中,其余的程序块则保留在磁盘中。
必要时,操作系统负责在磁盘和内存间交换程序块。
使用者感觉到程序可以使用非常大的内存空间,从而在写程序时不用考虑计算机中物理内存的实际容量。
为了支持虚拟存储管理器的管理,Linux系统采用分页的方式来载入进程。
所谓分页就是把实际的存储器分割为相同大小的段,例如每个段1024个字节,这样1024个字节大小的段便称为一个页面。
虚拟存储技术需要存储器管理机制及一个大容量快速硬盘存储器的支持,其实现基于局部性原理。
程序在运行之前,没有必要全部装入内存,而是仅将那些当前要运行的部分页面装入内存运行,其余暂时留在硬盘上。
运行程序时,如果它要访问的页已存在,则程序继续运行;如果发现不存在的页,操作系统将产生一个页错误,这个错误导致操作系统把需要运行的部分加载到内存中。
必要时操作系统还可以把不需要的内存页交换到磁盘上。
标准Linux 是针对有内存管理单元(MMU )的处理器设计的。
在这种处理器上,虚拟地址被送到内存管理单元映射为物理地址。
计算机的存储管理单元一般通过一组寄存器来标识当前运行进程的转换表。
在当前进程将CPU 移交给另一个进程时(一次上下文切换),内核通过指向新进程地址转换表的指针加载这些寄存器。
MMU 寄存器只能在内核态才能访问,这就保证了一个进程只能访问自己用户空间内的地址,而不会访问和修改其他进程的空间。
当可执行文件被加载时,加载器根据缺省的ld 文件,把程序加载到虚拟内存的一个空间,因此实际上很多很多程序的虚拟地址空间是相同的;但是由于转换函数不同,所以实际所处的内存区域也不同。
而对于多进程管理当处理器进行进程切换并执行一个新任务时,一个重要部分就是为新任务切换任务转换表。
Linux 虚拟内存的实现需要6种机制的支持:地址映射机制、内存分配回收机制、缓存和刷新机制、请求页机制、交换机制和内存共享机制。
内存管理程序通过映射机制把用户程序的逻辑地址映射到物理地址。
当用户程序运行时,如果发现程序中要用的虚拟地址没有对应的物理内存,就发出请求页要求。
如果有空闲的内存可供分配,就请求分配内存(于是用到了内存的分配和回收),并把正在使用的物理页记录在缓存中(使用了缓存机制)。
如果没有足够的内存可供分配,那么就调用交换机制,腾出一部分内存。
另外,在地址映射中要通过TLB (变换后援缓冲器)来寻找物理页,交换机制中要用到交换缓存,并且把物理页内容交换到交换文件中,也要修改页表来影射文件地址。
Linux 虚拟内存实现原理如图6.1所示。
内存分配和回收机制
图6.1 Linux 虚拟内存实现原理
虚拟内存技术不仅让我们可以使用更多的内存,它还提供了下面这些功能:
1. 巨大的寻址空间
操作系统让系统看上去有比实际内存大得多的内存空间。
虚拟内存可以是系统中实际物理空间的许多倍。
每个进程运行在其独立的虚拟地址空间中,这些虚拟空间相互之间都完全隔离,所以进程间不会互相影响。
同时,硬件虚拟内存机构可以将内存的某些区域设置成不可写,这样可以保护代码与数据不会受恶意程序的干扰。
2. 公平的物理内存分配
请求页机制 交 换 机 制
缓存和刷新机制 地址映射机制
内存管理子系统允许系统中每个运行的进程公平地共享系统中的物理内存。
3. 共享虚拟内存
尽管虚拟内存允许进程有其独立的虚拟地址空间,但有时也需要在进程之间共享内存。
共享内存可用来作为进程间通信的手段,多个进程通过共享来交换信息。
4. 进程保护
系统中的每一个进程都有自己的虚拟地址空间,这些虚拟地址空间是完全分开的,这样一个进程的运行不会影响其他进程,并且硬件上的虚拟内存机制是被保护的,内存不能被写入。