最后我们讲一下关于ucore编程里面
常用的一些编程的方法
让大家能够熟悉ucore编程的技巧
这里面主要强调一些
关于面向对象编程和通用数据结构的设计
那么ucore虽然是基于C语言开发的
但是它确实也产生了一些
面向对象一些编程手段 比如说在这里面
我们建立一个所谓物理内存的管理器
那叫pmm_manager
这个管理器它有很多一些函数的实现
它的表示是用函数指针的方式来实现
实际上对外暴露给需要访问物理内存管理器这些
调动者一个统一的接口 这个接口不会改变
但是你如果有不同的物理内存管理方法
比如说有不同连续内存的分配方法
那我们可以保持同样接口 但是它实现不一样
这个带来所谓统一的interface
但是它Details的实现不一样
面向对象设计的原则
我们来看看一般应用程序
怎么来用双向循环链表的
比如这么一个数据结构
这个数据结构需要通过双向链表形式
把它链接在一起 它有一个元素data
同时它也有一个prev前一个指针和next下一个指针
那么就形成了这么一个双向循环的链表
当然这种方式确实在应用程序开发里面常见
我们需要针对每一种特定的数据结构
都要建立类似的数据结构
这使得建立起来的数据结构不具有通用性
我们有没有更好的办法
我们以ucore双向链表结构来展示一下
我们定义一个通用的双向链表比如叫list_entry
这个也一样 你看到刚刚才类似Prev和next
但是这个Prev和next并不是特定结构的指针
它是一个通用结构指针 都是list_entry
假设我们想建立这么一个双向链表结构
它包含了free_area和page两种不同类型的strust
那我怎么来用这种方式来建立呢
我们先看free_area结构 free_area里面包含了两块
一块是free_list这free_list就是一个list_entry
第二个它中间的元素叫nr_free
这是一个特定一个它的元素
那么free_list就是这么一个数据结构
就是list_entry_t这么一个结构
你可以看到这里面就包含了两个指针
那么怎么跟page连接在一起呢 我们来看看
我们把page这个结构也是这么定义的
它自己一些比如reference
其它一些自己特定域在里面 成员变量在里面
但是它最后一个page_link
page_link也是一样也是list_entry数据结构
有了这两个之后 这个page_link
和free_list可以建立相应的链接关系
就通过prev和next来建立双向链接关系
这里面即满足了不同类型数据结构的
它们特定一些成员变量一些表示
而且在设计链接关系的时候
用的是一种通用的一种结构来表示
这是通用的双向链表的表示方式
应该说在我们ucore里面大量存在
这种方式大量存在
有了这种方式之后我们可以更灵活
更简洁来表示不同的资源
以及资源之间的关系
有了这个链表数据结构之后
我们还有相应对它进行操作的函数
这个函数的操作和我们通常链表操作差不多
有初始化 有增加删除等等
这都是不同函数的表示
其实还需要很重要一点
就是在于你怎么能够根据free_list的
或者说根据刚才说的page_link
它的结构能够找到它对应
整个数据结构起始位置
这个实际上有一定技巧
在这里面我们可以看看一个例子
怎么去访问链表的结点所在处的宿主数据结构
那这里面也有一样有free_area刚才说的变量
我们希望能够去以这个为头节点来查找
所有的free_area管理的page这么一个数据结构
那么它列出它一个方式
在这里面看起来和通常的轮巡方式是差不多
有一点不一样 需要注意在哪
它用到一个特殊的宏叫le2page这么一个结构
通过le2page来找到某一个page结构
变量的头指针在什么地方
这是它一个有特点的地方
那么le2page怎么实现的
这实际上是我们关心的
le2page它里面包含了两块
一个是指针 一个是member
这个指针是链表节点所在数据结构的指针
Member是它的名字 比如说在这里面
page这个结构里面它是叫做pagerank这两块
然后它是由另一个宏来执行的
就是to_struct 里面包含了三个内容
一个是le 一个是page 一个是member
这个page怎么体现 就是这个里面le2page
可以看出来它对一个特定的数据结构
那么它需要一个特定的结构在这里体现
那么这个结构到底怎么用 我们可以看到
那么to_struct又是这三块进一步的展开
这里面是等于这个链表节点的地址
减去一个offset这个offset是什么呢
就是减去它之前以page为例 它处于这个位置
前面的一个偏移值 它减去之后呢
实际上得到了 宿主数据结构头指针的一个信息
这就是offsetof 包含了一个type一个member
Type就是page member就是pagerank
这offsetof又是什么呢 这个表达式比较特殊
可以看出来 type*0 这个0代表什么意思呢
它不代表具体的一个地址
而是和在一起代表这种类型的
一个成员变量一个member成员变量
在这个类型中的一个偏移值
整个代表这么一个含义
那么有了这个含义之后
我就可以把这个offset得到一个偏移值之后呢
把ptr的地址减去那个偏移值
一个指针操作就可以得到这个page
数据结构的一个特定宿主变量它的地址在什么地方
那这个le2page这个宏呢
用到了三部分的内容 第一部分
是宿主数据结构的链表节点的指针就是le
第二个呢这个数据结构本身这个page这是第二块
第三块是这个链表所对应的这个成员变量的
名字叫member 有了这三个信息之后呢
最后通过关键的一种表达式 这么一种表达式
得出这个member 在这个数据结构中的offset
然后把这个节点的这个地址减去offset
就得到了这个宿主数据结构
所对应变量的头指针的地址
这就是它的大致结构
知道了这个之后呢后面就可以
用这种le2page等等 来完成
对特定数据结构的头指针一个寻址的的过程
这实际上是我们说 这个实验环境
重点需要大家去掌握的内容
好这部分内容就到这为止 谢谢大家