【转】Linux 概念架构的理解

转:http://mp.weixin.qq.com/s?__biz=MzA3NDcyMTQyNQ==&mid=400583492&idx=1&sn=3b18c463dcc45103b76a3419ceabe84c&scene=2&srcid=1213Z5CBO8W4jCmTSFI74uIb&from=timeline&isappinstalled=0#wechat_redirecthtml

Linux 概念架构的理解

2015-12-12 译者: 杜琪 Qunar技术沙龙

摘要

Linux kernel 成功的两个缘由:node

  1. 灵活的架构设计使得大量的志愿开发者可以很容易加入到开发过程当中;linux

  2. 每一个子系统(尤为是那些须要改进的)都具有良好的可扩展性。程序员

正是这两个缘由使得Linux kernel能够不断进化和改进。算法

 

 

1、Linux内核在整个计算机系统中的位置

Fig 1 - 计算机系统分层结构编程

分层结构的原则:安全

the dependencies between subsystems are from the top down: layers pictured near the top depend on lower layers, but subsystems nearer the bottom do not depend on higher layers.网络

这种子系统之间的依赖性只能是从上到下,也就是图中顶部的子系统依赖底部的子系统,反之则不行。数据结构

 

2、内核的做用

  1. 虚拟化(抽象),将计算机硬件抽象为一台虚拟机,供用户架构

    进程process

    使用;进程运行时彻底不须要知道硬件是如何工做的,只要调用 Linux kernel 提供的

    虚拟接口virtual interface

    便可。

  2. 多任务处理,其实是多个任务在并行使用计算机硬件资源,内核的任务是仲裁对资源的使用,制造每一个进程都觉得本身是独占系统的错觉。

PS:进程上下文切换就是要换掉程序状态字、换掉页表基地址寄存器的内容、换掉 current 指向的 task_struct 实例、换掉 PC ——>也就换掉了进程打开的文件(经过 task_struct 的 files 能够找到)、换掉了进程内存的执行空间(经过 task_struct 的 mem 能够找到);

 

3、Linux内核的总体架构

Linux内核的总体架构

中心系统是进程调度器Process Scheduler,SCHED:全部其他的子系统都依赖于进程调度器,由于其他子系统都须要阻塞和恢复进程。当一个进程须要等待一个硬件动做完成时,相应子系统会阻塞这个进程;当这个硬件动做完成时,子系统会将这个进程恢复:这个阻塞和恢复动做都要依赖于进程调度器完成。

上图中的每个依赖箭头都有缘由:

  • 进程调度器依赖

    内存管理器Memory manager

    :进程恢复执行时,须要依靠内存管理器分配供它运行的内存。

  • IPC 子系统依赖于内存管理器:共享内存机制是进程间通讯的一种方法,运行两个进程利用同一块共享的内存空间进行信息传递。

  • VFS 依赖于

    网络接口Network Interface

    :支持 NFS 网络文件系统;

  • VFS 依赖于内存管理器:支持 ramdisk 设备

  • 内存管理器依赖于 VFS,由于要支持

    交换swapping

    ,能够将暂时不运行的进程换出到磁盘上的

    交换分区swap

    ,进入挂起状态。

 

4、高度模块化设计的系统,利于分工合做。

  1. 只有极少数的程序员须要横跨多个模块开展工做,这种状况确实会发生,仅发生在当前系统须要依赖另外一个子系统时;

  2. 硬件设备驱动hardware device drivers

    文件系统模块logical filesystem modules

    网络设备驱动network device drivers

    网络协议模块network protocol modules

    这四个模块的可扩展性最高。

 

5、系统中的数据结构

  1. 任务列表Task List


    进程调度器针对每一个进程维护一个数据结构 task_struct;全部的进程用链表管理,造成 task list;进程调度器还维护一个 current 指针指向当前正在占用 CPU 的进程。

  2. 内存映射Memory Map


    内存管理器存储每一个进程的虚拟地址到物理地址的映射;而且也提供了如何换出特定的页,或者是如何进行缺页处理。这些信息存放在数据结构 mm_struct 中。每一个进程都有一个 mm_struct 结构,在进程的 task_struct 结构中有一个指针 mm 指向次进程的 mm_struct 结构。
    在 mm_struct 中有一个指针 pgd,指向该进程的页目录表(即存放页目录首地址)——>当该进程被调度时,此指针被换成物理地址,写入控制寄存器 CR3(x86体系结构下的页基址寄存器)

  3. I-nodes
    VFS 经过 inodes 节点表示磁盘上的文件镜像,inodes 用于记录文件的物理属性。每一个进程都有一个 files_struct 结构,用于表示该进程打开的文件,在 task_struct 中有个 files 指针。使用 inodes 节点能够实现文件共享。文件共享有两种方式:(1)经过同一个系统打开文件 file 指向同一个 inodes 节点,这种状况发生于父子进程间;(2)经过不一样系统打开文件指向同一个 inode 节点,举例有硬连接;或者是两个不相关的指针打开同一个文件。

  4. 数据链接Data Connection


    内核中全部的数据结构的根都在进程调度器维护的任务列表链表中。系统中每一个进程的的数据结构 task_struct 中有一个指针 mm 指向它的内存映射信息;也有一个指针 files 指向它打开的文件(用户打开文件表);还有一个指针指向该进程打开的网络套接字。

 

6、子系统架构

 

1.进程调度器Process Scheduler架构

 

(1)目标

进程调度器是 Linux kernel 中最重要的子系统。系统经过它来控制对 CPU 的访问——不只仅是用户进程对 CPU 的访问,也包括其他子系统对 CPU 的访问。

 

(2)模块

进程调度器

调度策略模块scheduling policy module:决定哪一个进程得到对 CPU 的访问权;调度策略应该让全部进程尽量公平得共享 CPU。

  • 体系结构相关模块architecture-specific module

    设计一组统一的抽象接口来屏蔽特定体系接口芯片的硬件细节。这个模块与 CPU 交互以阻塞和恢复进程。这些操做包括获取每一个进程须要保存的寄存器和状态信息、执行汇编代码来完成阻塞或者恢复操做。

  • 体系结构无关模块architecture-independent module

    与调度策略模块交互将决定下一个执行的进程,而后调用体系结构相关的代码去恢复那个进程的执行。不只如此,这个模块还会调用内存管理器的接口来确保被阻塞的进程的内存映射信息被正确得保存起来。

  • 系统调用接口模块system call interface

    容许用户进程访问 Linux Kernel 明确暴露给用户进程的资源。经过一组定义合适的基本上不变的接口(POSIX 标准),将用户应用程序和 Linux 内核解耦,使得用户进程不会受到内核变化的影响。

 

(3)数据表示

调度器维护一个数据结构——task list,其中的元素时每一个活动的进程 task_struct 实例;这个数据结构不只仅包含用来阻塞和恢复进程的信息,也包含额外的计数和状态信息。这个数据结构在整个 kernel 层均可以公共访问。

 

(4)依赖关系、数据流、控制流

正如前面提到过的,调度器须要调用内存管理器提供的功能,去为须要恢复执行的进程选择合适的物理地址,正由于如此,因此 进程调度器子系统依赖于内存管理子系统。当其余内核子系统须要等待硬件请求完成时,它们都依赖于进程调度子系统进行进程的阻塞和恢复。这种依赖性经过函数调用和访问共享的 task list 数据结构来体现。全部的内核子系统都要读或者写表明当前正在运行进程的数据结构,所以造成了贯穿整个系统的双向数据流。

除了内核层的数据流和控制流,OS 服务层还给用户进程提供注册定时器的接口。这造成了由调度器对用户进程的控制流。一般唤醒睡眠进程的用例不在正常的控制流范围,由于用户进程没法预知什么时候被唤醒。最后,调度器与 CPU 交互来阻塞和恢复进程,这又造成它们之间的数据流和控制流——CPU 负责打断当前正在运行的进程,并容许内核调度其余的进程运行。

 

2.内存管理器Memory Manager架构

 

(1)目标

内存管理模块负责控制进程如何访问物理内存资源。经过硬件内存管理系统(MMU)管理进程虚拟内存和机器物理内存之间的映射。每个进程都有本身独立的虚拟内存空间,因此两个进程可能有相同的虚拟地址,可是它们实际上在不一样的物理内存区域运行。MMU 提供内存保护,让两个进程的物理内存空间不互相干扰。内存管理模块还支持交换——将暂时不用的内存页换出到磁盘上的交换分区,这种技术让进程的虚拟地址空间大于物理内存的大小。虚拟地址空间的大小由机器字长决定。

 

(2)模块

内存管理子系统

  • 架构相关模块architecture specific module提供访问物理内存的虚拟接口;

  • 架构无关模块architecture independent module负责每一个进程的地址映射以及虚拟内存交换。当发生缺页错误时,由该模块负责决定哪一个内存页应该被换出内存——由于这个内存页换出选择算法几乎不须要改动,因此这里没有创建一个独立的策略模块。

  • 系统调用接口system call interface为用户进程提供严格的访问接口(malloc 和 free;mmap 和 ummap)。这个模块容许用进程分配和释放内存、执行内存映射文件操做。

 

(3)数据表示

内存管理存放每一个进程的虚拟内存到物理内存的映射信息。这种映射信息存放在 mm_struct 结构实例中,这个实例的指针又存放在每一个进程的 task_struct 中。除了存放映射信息,数据块中还应该存放关于内存管理器如何获取和存储页的信息。例如:可执行代码可以将可执行镜像做为备份存储;可是动态申请的数据则必须备份到系统页中。(这个没看懂,请高手解惑?)

最后,内存管理模块还应该存放访问和技术信息,以保证系统的安全。

 

(4)依赖关系、数据流和控制流

内存管理器控制物理内存,当页面失败page fault发生时,接受硬件的通知(缺页中断)—— 这意味着在内存管理模块和内存管理硬件之间存在双向的数据流和控制流。内存管理也依赖文件系统来支持交换和内存映射 I/O——这种需求意味着内存管理器须要调用对文件系统提供的函数接口procedure calls,往磁盘中存放内存页和从磁盘中取内存页。由于文件系统请求很是慢,因此在等待内存页被换入以前,内存管理器要让进程须要进入休眠——这种需求让内存管理器调用进程调度器的接口。因为每一个进程的内存映射存放在进程调度器的数据结构中,因此在内存管理器和进程调度器之间也有双向的数据流和控制流。用户进程能够创建新的进程地址空间,而且可以感知缺页错误——这里须要来自内存管理器的控制流。通常来讲没有用户进程到内存管理器的数据流,可是用户进程却能够经过 select 系统调用,从内存管理器获取一些信息。

 

3.虚拟文件系统Virtual File System架构

 

(1)目标

虚拟文件系统为存储在硬件设备上数据提供统一的访问接口。能够兼容不一样的文件系统(ext2,ext4,ntf等等)。计算机中几乎全部的硬件设备都被表示为一个通用的设备驱动接口。逻辑文件系统促进与其余操做系统标准的兼容性,而且容许开发者以不一样的策略实现文件系统。虚拟文件系统更进一步,容许系统管理员在任何设备上挂载任何逻辑文件系统。虚拟文件系统封装物理设备和逻辑文件系统的细节,而且容许用户进程使用统一的接口访问文件。

除了传统的文件系统目标,VFS 也负责装载新的可执行文件。这个任务由逻辑文件系统模块完成,使得 Linux 能够支持多种可执行文件。

 

(2)模块

虚拟文件系统模块

  • 设备驱动模块device driver module
  • 设备独立接口模块Device Independent Interface

    :提供全部设备的同一视图

  • 逻辑文件系统logical file system

    :针对每种支持的文件系统

  • 系统独立接口system independent interface

    提供硬件资源和逻辑文件系统都无关的接口,这个模块经过块设备节点或者字符设备节点提供全部的资源。

  • 系统调用模块system call interface

    提供用户进程对文件系统的统一控制访问。虚拟文件系统为用户进程屏蔽了全部特殊的特性。

 

(3)数据表示

全部文件使用 inode 表示。每一个 inode 都记录一个文件在硬件设备上的位置信息。不只如此,inode 还存放着指向逻辑文件系统模块和设备驱动的的函数指针,这些指针可以执行具体的读写操做。经过按照这种形式(就是面向对象中的虚函数的思想)存放函数指针,具体的逻辑文件系统和设备驱动能够向内核注册本身而不须要内核依赖具体的模块特性。

 

(4)依赖关系、数据流和控制流

一个特殊的设备驱动是 ramdisk,这个设备在主存中开辟一片区域,并把它当成持久性存储设备使用。这个设备驱动使用内存管理模块完成任务,因此在 VFS 与对内存管理模块存在依赖关系(图中的依赖关系反了,应该是 VFS 依赖于内存管理模块)、数据流和控制流。

逻辑文件系统支持网络文件系统。这个文件系统像访问本地文件同样,从另外一台机器上访问文件。为了实现这个功能,一种逻辑文件系统经过网络子系统完成它的任务——这引入了 VFS 对网络子系统的一个依赖关系以及它们之间的控制流和数据流。

正如前面提到的,内存管理器使用 VFS 完成内存交换功能和内存映射 I/O。另外,当 VFS 等待硬件请求完成时,VFS 须要使用进程调度器阻塞进程;当请求完成时,VFS 须要经过进程调度器唤醒进程。最后,系统调用接口容许用户进程调用来存取数据。不像前面的子系统,VFS 没有提供给用户注册不明确调用的机制,因此没有从VFS到用户进程的控制流。

 

4.网络接口Network Interface架构

 

(1)目标

网络子系统让 Linux 系统可以经过网络与其余系统相连。这个子系统支持不少硬件设备,也支持不少网络协议。网络子系统将硬件和协议的实现细节都屏蔽掉,并抽象出简单易用的接口供用户进程和其余子系统使用——用户进程和其他子系统不须要知道硬件设备和协议的细节。

 

(2)模块

网络协议层模块图

  • 网络设备驱动模块network device drivers
  • 设备独立接口模块device independent interface module

    提供全部硬件设备的一致访问接口,使得高层子系统不须要知道硬件的细节信息。

  • 网络协议模块network protocol modules

    负责实现每个网络传输协议,例如:TCP,UDP,IP,HTTP,ARP等等~

  • 协议无关模块protocol independent interface

    提供独立于具体协议和具体硬件设备的一致性接口。这使得其他内核子系统无需依赖特定的协议或者设备就能访问网络。

  • 系统调用接口模块system calls interface

    规定了用户进程能够访问的网络编程API

 

(3)数据表示

每一个网络对象都被表示为一个套接字socket。套接字与进程关联的方法和 inode 节点相同。经过两个 task_struct 指向同一个套接字,套接字能够被多个进程共享。

 

(4)数据流,控制流和依赖关系

当网络子系统须要等待硬件请求完成时,它须要经过进程调度系统将进程阻塞和唤醒——这造成了网络子系统和进程调度子系统之间的控制流和数据流。不只如此,虚拟文件系统经过网络子系统实现网络文件系统(NFS)——这造成了 VFS 和网络子系统指甲的数据流和控制流。

 

7、结论

一、Linux 内核是整个 Linux 系统中的一层。内核从概念上由五个主要的子系统构成:进程调度器模块、内存管理模块、虚拟文件系统、网络接口模块和进程间通讯模块。这些模块之间经过函数调用和共享数据结构进行数据交互。

二、Linux 内核架构促进了他的成功,这种架构使得大量的志愿开发人员能够合适得分工合做,而且使得各个特定的模块便于扩展。

  • 可扩展性一:Linux 架构经过一项数据抽象技术使得这些子系统成为可扩展的——每一个具体的硬件设备驱动都实现为单独的模块,该模块支持内核提供的统一的接口。经过这种方式,我的开发者只须要和其余内核开发者作最少的交互,就能够为 Linux 内核添加新的设备驱动。

  • 可扩展性二:Linux 内核支持多种不一样的体系结构。在每一个子系统中,都将体系结构相关的代码分割出来,造成单独的模块。经过这种方法,一些厂家在推出他们本身的芯片时,他们的内核开发小组只须要从新实现内核中机器相关的代码,就能够讲内核移植到新的芯片上运行。

 

参考文章:

http://oss.org.cn/ossdocs/linux/kernel/a1/index.html

http://www.cs.cmu.edu/afs/cs/project/able/www/paper_abstracts/intro_softarch.html

http://www.cs.cmu.edu/afs/cs/project/able/www/paper_abstracts/intro_softarch.html

http://www.fceia.unr.edu.ar/ingsoft/monroe00.pdf
内核源码:http://lxr.oss.org.cn/

来源:简书 参考原文:http://oss.org.cn/ossdocs/linux/kernel/a1/index.html               做者: Ivan Bowman

编译文章:http://www.jianshu.com/p/c5ae8f061cfe                                               译者: 杜琪

相关文章
相关标签/搜索