购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.1 常见架构范式与核心系统

在Linux内核中使用了很多“约定俗成”的架构上的约定,这些约定大部分被C语言开发者所熟知,并被广泛应用到日常的使用C语言开发的应用中。

2.1.1 Linux内核上下层通信方式

定义一个结构体,包含各种函数指针并且管理其列表。下层通过生成一个这样的结构体,将自己的操作函数赋值给该结构体的对应域,然后调用上层的注册函数,将自己的信息注册到上层。这样上层就可以用统一的函数调用不同的下层接口。上层可以遍历,通过名字或设置哪个函数有效来确定调用哪个下层结构体对应的同名操作。这种方式使用了C语言,同时融入了面向接口和面向过程的编程思路。一个典型的例子如下。

例如这个结构体(linux/fs.h)就是定义了一些约定的函数指针。当上层调用一个下层的函数时,一般有3种返回值的方式,第1种是通过语言规定的函数返回值(在大部分情况下);第2种是传递的参数是指向结果的指针(例如writepage函数的wbc参数);第3种是使用回调函数(在内核中有广泛用处),通常让用户提供执行过程的某一处逻辑甚至是用户定义的返回结果。回调函数通常是调用者提供的。

内核首先按照功能分成了几个大型的子系统,再通过上下层通信的方式将内核各个子系统有效地分成了层级关系,使得架构清晰。虽然这个手法并不一定是Linux首创,但后续无数的C语言程序员都受到这种“风格”的影响,可以说是C语言中的软件工程“导师级”的作品。

1.资源竞争处理

内核的主要工作就是安排资源,而Linux是支持多进程的,这对资源竞争的处理就不可避免。内核在架构级别的资源竞争处理的主要思路是队列缓存,例如将磁盘读写产生的bio结构体提交给设备,当其发现设备忙时就将该请求加入队列,然后返回,如果设备不忙就直接提交。实现方式比较有趣,利用对象的队列指针判断设备是否繁忙。如果队列指针为空,则说明设备不忙。如果设备忙,该指针则不为空。

针对细节的资源竞争,Linux提供了很多的锁的实现。如果Linux出现了不能满足需求的低效事件,那么基本上都是由于这些锁导致的。这些锁在第5.3节中有比较详细的介绍。

2.Linux内核的结构体

Linux的结构体之间可以有继承关系,但不是C++那种显式的继承,而是子结构体包含了父接口体的指针,通过子结构体可以找到父结构体。而子结构体可以继承多个父结构体,就像C++里面所说的强引用关系。示例如下:

总体来说,Linux有两种结构体模型,一种是对对象的建模;另一种是对操作的建模。两个体系互相有交叉关系,又各有各的继承结构。

Linux很多重要对象的结构体中的域都是为各个层次的各个功能使用的。开发者在写代码的时候出于一定的理由,需要在结构体提供某个域以完成自己的功能,这就会在其中找地方添加,而这个添加通常导致不同层级的需求被糅合在一个大型的结构体里,最后导致的结果就是非常难懂,得熟悉了组成结构体的细节组件之后才能有一定的理解。所以看Linux的结构体必须要对应细节功能,而一个结构体中的功能的跨度可能很大,所以看这种代码学习曲线很高,必须要全面地理解内核后才能看懂部分代码,所以就需要迭代渐进地阅读和学习。

2.1.2 横向系统和纵向系统

横向系统不是指具体的物理功能,而是指各个功能模块都需要对外展示的接口。例如cgroup、proc、sys文件系统、系统调用的组织、调试系统、Core Dump、信号、内存管理等,以及内核提供的基础元素功能,例如workqueue、tasklet、pipe等。

在使用Linux时,横向系统是通用工具意义上的存在,无论研究Linux的哪个方面,都应该掌握横向系统,但是横向系统也没有绝对的划分。

纵向系统是指具体的功能模块,这些模块总体像是一个森林,不同的功能树下面有很多的层次。例如一个用户端对USB文件的操作要走完内核中的很多个层次,即文件系统层、缓存层、通用块层、SCSI层、USB层,每个层次的内部又分为多个层次。但Linux内核一般将它们分为3个层次,为上层提供统一接口的接口层,中间实现主要逻辑的功能层和统一下层不同驱动接口的驱动层。

不同层次有不同分工,它们按照顺序完成工作,一整条链路下来就是Linux的一个纵向的子系统。例如文件系统层解释文件在磁盘中存储的物理布局;缓存层实现读写请求在内存中的存放方式(预读、延迟写等);通用块层处理上层多个请求的调度(例如合并、排序);SCSI层负责把上层命令的内容转变为设备可以识别的SCSI指令;USB层负责把指令成功地送达给对应的设备。

使用Linux作为后台开发系统的开发者大部分情况是使用CPU的运算能力和网络的联通能力。而嵌入式开发者可能会关注Linux的热插拨服务,有的则会格外重视电源管理等。

很多Linux内核提供的服务都是互相交错的,所以横向与纵向的界限并不明显,这里的区别只是存在于对概念理解上。 XCKcQS9dYmnngbIouoxMLKT39I8AOGT78KFf+DTdpGPDjEREEOyFgrV7Ucbu3vt+

点击中间区域
呼出菜单
上一章
目录
下一章
×