当前课程知识点:操作系统 > 第二讲 实验零 操作系统实验环境准备 > 2.6 ucore部分编程技巧 > 2.6 ucore部分编程技巧
最后我们讲一下关于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等等 来完成
对特定数据结构的头指针一个寻址的的过程
这实际上是我们说 这个实验环境
重点需要大家去掌握的内容
好这部分内容就到这为止 谢谢大家
-0.1 Piazza讨论区
--html
-0.2 在线实验平台
--实验平台使用帮助
--平台使用帮助
-0.2在线实验平台
--Raw HTML
-1.1 课程概述
--视频
-第一讲 操作系统概述--练习
-1.2 教学安排
--视频
-1.3 什么是操作系统
--Video
-1.4 为什么学习操作系统,如何学习操作系统
--Video
-1.5 操作系统实例
--视频
-1.6 操作系统的演变
--视频
-1.7 操作系统结构
--视频
-2.1 前言和国内外现状
-2.2 OS实验目标
-2.3 8个OS实验概述
-2.4 实验环境搭建
-2.5 x86-32硬件介绍
-2.6 ucore部分编程技巧
-2.7 演示实验操作过程
--Q6
--Q7
--Q10
-3.1 BIOS
--3.1 BIOS
-3.2 系统启动流程
-3.3 中断、异常和系统调用比较
-第三讲 启动、中断、异常和系统调用--3.3 中断、异常和系统调用比较
-3.4 系统调用
--3.4 系统调用
-第三讲 启动、中断、异常和系统调用--3.4 系统调用
-3.5 系统调用示例
-3.6 ucore+系统调用代码
-4.1 启动顺序
--4.1 启动顺序
-4.2 C函数调用的实现
-4.3 GCC内联汇编
-4.4 x86中断处理过程
-4.5 练习一
--4.5 练习一
-4.6 练习二
--4.6 练习二
-4.7 练习三
--4.7 练习三
-4.8 练习四 练习五
-4.9 练习六
--4.9 练习六
-5.1 计算机体系结构和内存层次
-5.2 地址空间和地址生成
-5.3 连续内存分配
-5.4 碎片整理
--5.4 碎片整理
-5.5 伙伴系统
--5.5 伙伴系统
-第五讲 物理内存管理: 连续内存分配--5.6 练习
-6.1 非连续内存分配的需求背景
-6.2 段式存储管理
-- 6.2 段式存储管理
-6.3 页式存储管理
-6.4 页表概述
--6.4 页表概述
-6.5 快表和多级页表
-6.6 反置页表
--6.6 反置页表
-6.7 段页式存储管理
-第六讲 物理内存管理: 非连续内存分配--6.8 练习
-7.1 了解x86保护模式中的特权级
-第七讲 实验二 物理内存管理--7.1 了解x86保护模式中的特权级
-7.2 了解特权级切换过程
-第七讲 实验二 物理内存管理--7.2 了解特权级切换过程
-7.3 了解段/页表
-第七讲 实验二 物理内存管理--7.3 了解段/页表
-7.4 了解UCORE建立段/页表
-第七讲 实验二 物理内存管理--7.4 了解UCORE建立段/页表
-7.5 演示lab2实验环节
-8.1 虚拟存储的需求背景
-8.2 覆盖和交换
-8.3 局部性原理
-8.4 虚拟存储概念
-8.5 虚拟页式存储
-8.6 缺页异常
--8.6 缺页异常
-9.1 页面置换算法的概念
-9.2 最优算法、先进先出算法和最近最久未使用算法
-第九讲 页面置换算法--9.2 最优算法、先进先出算法和最近最久未使用算法
-9.3 时钟置换算法和最不常用算法
-第九讲 页面置换算法--9.3 时钟置换算法和最不常用算法
-9.4 Belady现象和局部置换算法比较
-第九讲 页面置换算法--9.4 Belady现象和局部置换算法比较
-9.5 工作集置换算法
-第九讲 页面置换算法--9.5 工作集置换算法
-9.6 缺页率置换算法
-第九讲 页面置换算法--9.6 缺页率置换算法
-9.7 抖动和负载控制
-10.1 实验目标:虚存管理
-第十讲 实验三 虚拟内存管理--10.1 实验目标:虚存管理
-10.2 回顾历史和了解当下
-第十讲 实验三 虚拟内存管理--10.2 回顾历史和了解当下
-10.3 处理流程、关键数据结构和功能
-第十讲 实验三 虚拟内存管理--10.3 处理流程、关键数据结构和功能
-10.4 页访问异常
-第十讲 实验三 虚拟内存管理--10.4 页访问异常
-10.5 页换入换出机制
-第十讲 实验三 虚拟内存管理--10.5 页换入换出机制
-11.1 进程的概念
-第十一讲 进程和线程--11.1 进程的概念
-11.2 进程控制块
-第十一讲 进程和线程--11.2 进程控制块
-11.3 进程状态
-第十一讲 进程和线程--11.3 进程状态
-11.4 三状态进程模型
-11.5 挂起进程模型
-第十一讲 进程和线程--11.5 挂起进程模型
-11.6 线程的概念
-第十一讲 进程和线程--11.6 线程的概念
-11.7 用户线程
-第十一讲 进程和线程--11.7 用户线程
-11.8 内核线程
-第十一讲 进程和线程--11.8 内核线程
-12.1 进程切换
-第十二讲 进程控制--12.1 进程切换
-12.2 进程创建
-第十二讲 进程控制--12.2 进程创建
-12.3 进程加载
-第十二讲 进程控制--12.3 进程加载
-12.4 进程等待与退出
-第十二讲 进程控制--12.4 进程等待与退出
-13.1 总体介绍
-13.2 关键数据结构
-13.3 执行流程
-13.4 实际操作
-14.1 总体介绍
-14.2 进程的内存布局
-14.3 执行ELF格式的二进制代码-do_execve的实现
--14.3 执行ELF格式的二进制代码-do_execve的实现
-14.4 执行ELF格式的二进制代码-load_icode的实现
--14.4 执行ELF格式的二进制代码-load_icode的实现
-14.5 进程复制
-14.6 内存管理的copy-on-write机制
-15.1 处理机调度概念
-第十五讲 处理机调度--15.1 处理机调度概念
-15.2 调度准则
-15.3 先来先服务、短进程优先和最高响应比优先调度算法
--15.3 先来先服务、短进程优先和最高响应比优先调度算法
-第十五讲 处理机调度--15.3 先来先服务、短进程优先和最高响应比优先调度算法
-15.4 时间片轮转、多级反馈队列、公平共享调度算法和ucore调度框架
--15.4 时间片轮转、多级反馈队列、公平共享调度算法和ucore调度框架
-第十五讲 处理机调度--15.4 时间片轮转、多级反馈队列、公平共享调度算法和uc
-15.5 实时调度和多处理器调度
-第十五讲 处理机调度--15.5 实时调度和多处理器调度
-15.6 优先级反置
-第十五讲 处理机调度--15.6 优先级反置
-16.1 总体介绍和调度过程
-16.2 调度算法支撑框架
-16.3 时间片轮转调度算法
-16.4 Stride调度算法
-17.1 背景
--17.1 背景
-17.2 现实生活中的同步问题
-第十七讲 同步互斥--17.2 现实生活中的同步问题
-17.3 临界区和禁用硬件中断同步方法
-第十七讲 同步互斥--17.3 临界区和禁用硬件中断同步方法
-17.4 基于软件的同步方法
-第十七讲 同步互斥--17.4 基于软件的同步方法
-17.5 高级抽象的同步方法
-第十七讲 同步互斥--17.5 高级抽象的同步方法
-18.1 信号量
--18.1 信号量
-第十八讲 信号量与管程--18.1 信号量
-18.2 信号量使用
-第十八讲 信号量与管程--18.2 信号量使用
-18.3 管程
--18.3 管程
-第十八讲 信号量与管程--18.3 管程
-18.4 哲学家就餐问题
-18.5 读者-写者问题
-19.1 总体介绍
-19.2 底层支撑
-第十九讲 实验七 同步互斥--19.2 底层支撑
-19.3 信号量设计实现
-第十九讲 实验七 同步互斥--19.3 信号量设计实现
-19.4 管程和条件变量设计实现
-第十九讲 实验七 同步互斥--19.4 管程和条件变量设计实现
-19.5 哲学家就餐问题
-20.1 死锁概念
-第二十讲 死锁和进程通信--20.1 死锁概念
-20.2 死锁处理方法
-第二十讲 死锁和进程通信--20.2 死锁处理方法
-20.3 银行家算法
-第二十讲 死锁和进程通信--20.3 银行家算法
-20.4 死锁检测
-第二十讲 死锁和进程通信--20.4 死锁检测
-20.5 进程通信概念
-第二十讲 死锁和进程通信--20.5 进程通信概念
-20.6 信号和管道
-第二十讲 死锁和进程通信--20.6 信号和管道
-20.7 消息队列和共享内存
-第二十讲 死锁和进程通信--20.7 消息队列和共享内存
-21.1 文件系统和文件
-第二十一讲 文件系统--21.1 文件系统和文件
-21.2 文件描述符
-第二十一讲 文件系统--21.2 文件描述符
-21.3 目录、文件别名和文件系统种类
-第二十一讲 文件系统--21.3 目录、文件别名和文件系统种类
-21.4 虚拟文件系统
-第二十一讲 文件系统--21.4 虚拟文件系统
-21.5 文件缓存和打开文件
-第二十一讲 文件系统--21.5 文件缓存和打开文件
-21.6 文件分配
-第二十一讲 文件系统--21.6 文件分配
-21.7 空闲空间管理和冗余磁盘阵列RAID
-第二十一讲 文件系统--21.7 空闲空间管理和冗余磁盘阵列RAID
-22.1 总体介绍
-第二十二讲 实验八 文件系统--22.1 总体介绍
-22.2 ucore 文件系统架构
-第二十二讲 实验八 文件系统--22.2 ucore 文件系统架构
-22.3 Simple File System分析
-第二十二讲 实验八 文件系统--22.3 Simple File System分析
-22.4 Virtual File System分析
-第二十二讲 实验八 文件系统--22.4 Virtual File System分
-22.5 I/O设备接口分析
-第二十二讲 实验八 文件系统--22.5 I/O设备接口分析
-22.6 执行流程分析
-23.1 I/O特点
--视频
-第二十三讲 I/O子系统--23.1 I/O特点
-23.2 I/O结构
--816C80A0F5E3B8809C33DC5901307461
-第二十三讲 I/O子系统--23.2 I/O结构
-23.3 I/O数据传输
--C58221E14388B9DB9C33DC5901307461
-第二十三讲 I/O子系统--23.3 I/O数据传输
-23.4 磁盘调度
--567A3F1FCBFB3F4C9C33DC5901307461
-第二十三讲 I/O子系统--23.4 磁盘调度
-23.5 磁盘缓存
--C327536B80D25CE79C33DC5901307461
-第二十三讲 I/O子系统--23.5 磁盘缓存
-html
--html