任何计算机系统都包含一个名为操作系统的基本程序集合。在这个集合里,最重要的程序称为内核(kernel)。当操作系统启动时,内核被装入到RAM中,内核中包含了系统运行所必不可少的很多核心过程(procedure)。其他程序是一些不太重要的使用程序,尽管这些程序为用户提供了与计算机进行广泛交流的经验(以及用户买计算机要做的所有工作),但系统根本的样子和能力还是由内核决定。内核也为系统中所有事情提供了主要功能,并决定高层软件的很多特性。因此,我们将经常使用术语“操作系统”作为“内核”的同义词。
RAM(Random Access Memory)是一种计算机内存,它允许数据被随机地读取和写入。与只读存储器(ROM)不同,RAM只能临时存储数据,当电源关闭时,存储在RAM中的数据会丢失。
RAM通常由多个存储单元组成,每个单元可以存储一个二进制数字(0或1)。这些存储单元被组织成一个矩阵,方便数据的随机访问。现代计算机通常包含几个GB的RAM,以便快速处理大量数据。
根据工作原理,RAM可以分为两类:静态RAM(SRAM)和动态RAM(DRAM)。SRAM的每个存储单元都需要六个晶体管,因此它的集成度较低,功耗也较高。相比之下,DRAM的每个存储单元只需要一个晶体管和一个小电容,因此它的集成度更高,功耗更低。
除了SRAM和DRAM,还有一种基于Flash技术的非易失性RAM(NVRAM),它可以在断电后保持数据。NVRAM通常用于存储固件、启动加载器等重要数据。
总之,RAM是计算机中非常重要的组成部分,它提供了快速的数据存储和访问能力,使得计算机能够高效地处理各种任务。
操作系统必须完成两个主要目标:
与硬件部分交互,为包含在硬件平台上的所有低层可编程部件提供服务。
为运行在计算机系统上的应用程序(即所谓用户程序)提供执行环境。
一些操作系统允许所有的用户程序都与硬件部分进行交互(典型的例子是MS-DOS)。与此相反,类Unix操作系统把与计算机物理组织相关的所有低层细节都对用户运行的程序隐藏起来。当程序想使用硬件资源时,必须向操作系统发出一个请求。内核对这个请求进行评估,如果允许使用这个资源,那么,内核代表应用程序与相关的硬件部分进行交互。
为了实施这种机制,现代操作系统依靠特殊的硬件特性来禁止用户程序直接与低层硬件部分进行交互,或者禁止直接访问任意的物理地址。特别是,硬件为CPU引入了至少有两种不同的执行模式:用户程序的非特权模式和内核的特权模式。Unix把它们分别称为用户态(User Mode)和内核态(Kernel Mode)。
下面这些基本概念,推动了Unix、Linux和其他操作系统的设计。你也许熟悉这些概念,但为了说明这些概念对Linux内核的必要性,下面试图对其做更深一步的介绍。
多用户系统
多用户系统(multiuser system)就是一台能并发和独立地执行分别属于两个或多个用户的若干应用程序的计算机。“并发”(concurrently)意味着几个应用程序能同时处于活动状态并竞争各种资源,如CPU、内存、硬盘等等。“独立”(independently)意味着每个应用程序能执行自己的任务,而无需考虑其他用户的应用程序在干些什么。当然,从一个应用程序切换到另一个会使每个应用程序的速度有所减慢,从而影响用户看到的响应时间。现代操作系统内核提供的许多复杂特性减少了强加在每个程序上的延迟时间,给用户提供了尽可能快的响应时间。
多用户操作系统必须包含以下几个特点:
核实用户身份的认证机制。
防止有错误的用户程序妨碍其他应用程序在系统中运行的保护机制。
防止有恶意的用户程序干涉或窥视其他用户的活动的保护机制。
限制分配给每个用户的资源数的记账机制。
为了确保能实现这些安全保护机制,操作系统必须利用与CPU特权模式相关的硬件保护机制,否则,用户程序将能直接访问系统电路并克服强加于它的这些限制。Unix是实施系统资源硬件保护的多用户系统。
用户和组
在多用户系统中,每个用户在机器上都有私有空间,典型地,他拥有一定数量的磁盘空间来存储文件、接收私人邮件信息等等。操作系统必须保证用户空间的私有部分仅仅对其拥有者是可见的。特别是必须能保证,没有用户能够开发一个用于侵犯其他用户私有空间的系统应用程序。
所有的用户由一个唯一的数字来标识,这个数字叫用户标识符(User ID, UID)。通常一个计算机系统只能由有限的人使用。当其中的某个用户开始一个工作会话时,操作系统要求输入一个登录名和口令,如果用户输入的信息无效,则系统拒绝访问。因为口令是不公开的,所以用户的保密性得到了保证。
为了和其他用户有选择地共享资料,每个用户是一个或多个用户组的一名成员,组由唯一的用户组标识符(user group ID)标识。每个文件也恰好与一个组相对应。例如,可以设置这样的访问权限,拥有文件的用户具有对文件的读写权限,同组用户仅有只读权限,而系统中的其他用户没有对文件的任何访问权限。
任何类Unix操作系统都有一个特殊的用户,叫做root,即超级用户(superuser)。系统管理员必须以root的身份登录,以便处理用户账号,完成诸如系统备份、程序升级等维护任务。root用户几乎无所不能,因为操作系统对他不使用通常的保护机制。尤其是,root用户能访问系统中的每一个文件,能干涉每一个正在执行的用户程序的活动。
进程
所有的操作系统都使用一种基本的抽象:进程(Process)。一个进程可以定义为:“程序执行时的一个实例”,或者一个运行程序的“执行上下文”。在传统的操作系统中,一个进程的地址空间(address space)中执行一个单独的指令序列。地址空间是允许进程引用的内存地址集合。现代操作系统允许具有多个执行流的进程,也就是说,在相同的地址空间可执行多个指令序列。
多用户系统必须实施一种执行环境,在这种环境里,几个进程能并发活动,并能竞争系统资源(主要是CPU)。允许进程并发活动的系统称为多道程序系统(multiprogramming)或多处理系统(multiprocessing)。区分程序和进程是非常重要的:几个进程能并发地执行同一个程序,而同一个进程能顺序地执行几个程序。
在单处理器系统上,只有一个进程能占用CPU,因此,在某一时刻只能有一个执行流。一般来说,CPU的个数总是有限的,因而只有少数几个进程能同时执行。操作系统中叫做调度程序(scheduler)的部分决定哪个进程能执行。一些操作系统只运行有非抢占式(nonpreemptable)进程,这就意味着,只有当进程资源放弃CPU时,调度程序才被调用。但是,多用户系统中的进程必须是抢占式的(preemptable),操作系统记录下每个进程占有的CPU时间,并周期性地激活调度程序。
Unix是具有抢占式进程的多处理操作系统。即使没有用户登录,没有程序运行,也还是有几个系统进程在监视外围设备。尤其是,有几个进程在监听系统终端等待用户登录。当用户输入一个登录名,监听进程就运行一个程序来验证用户的口令。如果用户身份得到证实,那么监听进程就创建另一个进程来执行shell,此时在shell下可以输入命令。当一个图形化界面被激活时,有一个进程就运行窗口管理器,界面上的每个窗口通常都由一个单独的进程来执行。如果用户创建了一个图形化shell,那么一个进程运行图形化窗口,而第二个进程运行用户可以输入命令的shell,对每一个用户命令,shell进程都创建执行响应程序的另一个进程。
类Unix操作系统采用进程/内核模式。每个进程都自以为它是系统中唯一的进程,可以独占操作系统所提供的服务。只是进程发出系统调用,硬件就会把特权模式由用户态变成内核态,然后进程以非常有限的目的开始一个内核过程的执行。这样,操作系统在进程的执行上下文中起作用,以满足进程的请求。一旦这个请求完全得到满足,内核过程将迫使硬件返回到用户态,然后进程从系统调用的下一条指令继续执行。
内核体系结构
如前所述,大部分Unix内核是单块结构:每一个内核层都被继承到整个内核程序中,并代表当前进程在内核态下运行。相反,微内核(microkernel)操作系统只需要内核有一个很小的函数集,通常包括几个同步原语、一个简单的调度程序和进程间通信机制。运行在微内核之上的几个系统进程实现从前操作系统级实现的功能,如内存分配程序、设备驱动程序、系统调用处理程序等等。
尽管关于操作系统的学术研究都是面向微内核的,但这样的操作系统一般比单块内核的效率低,因为操作系统不同层次之间显式的消息传递要花费一定的代价。不过,微内核操作系统比单块内核有一定的理论优势。微内核操作系统迫使系统程序员采用模块化的方法,因为任何操作系统层都是一个相对独立的程序,这种程序必须通过定义明确而清晰的软件接口与其他层交互。此外,已有的微内核操作系统可以很容易地移植到其他的体系结构上,因为所有与硬件相关的部分都被封装进微内核代码中。最后,微内核操作系统比单块内核更加充分地利用了RAM,因为暂且不需要执行的系统进程可以被调出或撤销。
为了达到微内核理论上的很多优点而又不影响性能,Linux内核提供了模块(module)。模块是一个目标文件,其代码可以在运行时链接到内核或从内核解除链接。这种目标代码通常由一组函数组成,用来实现文件系统、驱动程序或其他内核上层功能。与微内核操作系统的外层不同,模块不是作为一个特殊的进程执行的。相反,与任何其他静态链接的内核函数一样,它代表当前进程在内核态下执行。
使用模块的主要优点包括:
模块化方法
因为任何模块都可以在运行时被链接或解除链接,因此,系统程序员必须提出良定义的软件接口以访问由模块处理的数据结构。这使得开发新模块变得容易。
平台无关性
即使模块依赖于某些特殊的硬件特点,但它不依赖于某个固定的硬件平台。例如,符合SCSI标准的磁盘驱动程序模块,在IBM兼容PC与HP的Alpha机上都能很好地工作。
节省内存使用
当需要模块功能时,把它链接到正在运行的内核中,否则,将该模块解除链接。这种机制对于小型嵌入式系统是非常有用的。
无性能损失
模块的目标代码一旦被链接到内核,其作用与静态链接的内核的目标代码完全等价。因此,当模块的函数被调用时,无需显式地进行消息传递。
参考文档:
[1] 《深入理解Linux内核第三版》
欢迎 点赞 收藏⭐ 评论 关注❤ 如有错误敬请指正!
☟ 学Python,点击下方名片关注我。☟