《操作系统真象还原》-阅读笔记(下)

第十一章

任意进程的页目录表第0~767个页目录项属于用户空间,指向用户页表。第768~1023个页目录项指向内核页表。每创建一个新的用户进程,就将内核页目录项复制到用户进程的页目录表,其次需要把用户页目录表中最后一个页目录项更新为用户进程自己的页目录表的物理地址。
每个进程有自己单独的位图,存储在进程pcb中的userprog_vaddr中。
LDT
当前运行的任务,其LDT位于LDTR指向的地址(选择子)。每切换一个任务时,需要lldt指令重新加载新任务的LDT到LDTR
TSS
CPU自动用此结构体变量保存任务的状态(任务的上下文环境,寄存器的值)和自动从此结构体变量中载入任务的状态。TR寄存器始终指向当前任务的TSS,这样每个任务必须有单独的TSS,但Linux并未这么做。Linux所有任务共享一个TSS。
除了中断和调用门返回外,CPU不允许从高特权级到低特权级。CPU在不同的特权级下使用不同的栈。
TSS和LDT一样,必须要在GDT中注册。
现代操作系统采用的任务切换方式
我们使用TSS的唯一理由是为0特权级的任务提供栈。
Linux中为每个CPU创建一个TSS,在各个CPU上的所有任务共享同一个TSS,各CPU的TR寄存器保存各自的TSS,在用ltr指令加载TSS后,TR寄存器永远指向同一个TSS,进程切换时只把这个TSS中的SS0和esp0更新为新任务的内核栈的段地址和栈指针。


第十二章

系统调用
Linux只占用一个中断向量号0X80,在寄存器eax中写入子功能号。所有系统调用都可以通过syscall函数(不是由系统提供的,是glibc提供的库函数,直接系统调用为_syscall)完成。总之对用户进程而言,在 Linux 上执行系统调用,只需要提供子功能号和参数就行了。
堆内存管理
arena
将一大块内存划分为无数小内存块的内存仓库。
arena 是个提供内在分配的数据结构,它分为两部分,一部分是元信息,用来描述自己内存池中空闲内存块数量,这其中包括内存块描述符指针(后面介绍),通过它可以间接获知本 arena 所包含内存块的规格大小,此部分占用的空间是固定的,约为 12 字节。另一部分就是内存地区域,这里面有无数的内存块,此部分占用 arena 大量的空间。
本书中针对小内存块的arena占用1页框内存。
每个内存块命名为mem_block,分别为每一种规格的内存块建立一个内存块描述符即mem_bloc_desc。

struct mem_block_desc (
uint32 t block size //内存块大小
uint32_t blocks_per_arena; //本arena中可容纳此 mem_block 的数量
struct list free list //目前可用同类的mem_block链表


实现sys_malloc
传入参数size,代表申请多少字节内存
1.首先判断用哪个内存池,内核还是用户
2.若申请的内存不在内存池容量范围内,直接返回NULL
3.超过1024就直接分配页框
4.若小于等于1024,循环各种规格,找到最合适的规格
5.判断该规格free_list是否为空,若mem_block_desc的free_list中已经没有可用的mem_block,就创建新的arena提供mem_block
6.从free_list中弹出一个内存块,通过elem2entry宏转换成mem_block的地址,返回内存块地址
内存释放(页框级别)
分配内存的步骤
1.虚拟地址池中分配虚拟地址,操作位图
2.物理内存池中分配物理地址,操作位图
3.完成虚拟地址和物理地址的映射
释放内存的步骤
1.释放物理页地址,操作位图
2.在页表中去掉虚拟地址的映射,将虚拟地址对应pte的P位置0
3.在虚拟地址中释放虚拟地址,操作位图
当物理内存不多时,就将其数据移到硬盘中,然后对应页表项pte的P位置0,当CPU访问时会引发pagefault中断,中断处理程序将数据物理页更新到pte中,再将P位置1,CPU会再次访问引起pagefault的虚拟地址。
实现sys_free
对于大内存,就是把页框在虚拟内存池和物理内存池的位图中相应位置0。
对于小内存,是将arena中的内存块重新放回到内存块描述符的空闲块链表free_list。

第十三章

编写硬盘驱动(略)

第十四章

硬盘的读写单位是扇区,数据一般积攒到足够大小才一次性访问硬盘,足够大小的数据就是块,一个块由多个扇区构成。
FAT32
用链表的方式来连接每个数据块,查询某个数据块很耗时
inode
控制,管理文件相关信息的数据结构是FCB,inode就是其中一种。
用索引来查找数据块,在UNIX系统中,一个文件必须对应一个inode(索引表),磁盘中有多少文件就有多少个inode。inode的结构如下如图,前12个索引为直接指针,后面的3个为间接索引的地址。每个间接索引表都可存256个块。


在Linux中每分区inode数量是固定的,分区中所有文件的inode通过一个大表格来维护,此表格称为inode_table。
目录项
通过文件名找文件实体数据的流程是:
1.在目录中找到文件名所在的目录项
2.从目录项中获取inode编号
3.用inode编号作为inode数组的索引下标,找到inode
4.从该inode中获取数据块的地址,读取数据块

目录项仅存在于inode指向的数据块中,有目录项的数据块就是目录,目录项所属的inode指向的所有数据块便是目录。
每个分区都有自己的根目录,根目录/的位置是固定不变的,查找任意文件时,都直接到根目录的数据块中找相关的目录项,然后递归查找,最终可以找到任意子目录中的文件。

超级块
超级块是保存文件系统元信息的元信息。它被固定在各分区的第2个扇区。

文件系统布局
Linux早期文件系统布局如下图

第十五章

fork
fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,Linux中引入了“写时复制“技术,也就是只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。在fork之后exec之前两个进程用的是相同的物理空间(内存区),子进程的代码段、数据段、堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个。当父子进程中有更改相应段的行为发生时,再为子进程相应的段分配物理空间,如果不是因为exec,内核会给子进程的数据段、堆栈段分配相应的物理空间(至此两者有各自的进程空间,互不影响),而代码段继续共享父进程的物理空间(两者的代码完全相同)。而如果是因为exec,由于两者执行的代码不同,子进程的代码段也会分配单独的物理空间。
为什么fork后父子进程同一个变量地址打印出来相同
假定父进程malloc的指针指向0x12345678, fork 后,子进程中的指针也是指向0x12345678,但是这两个地址都是虚拟内存地址 (virtual memory),经过内存地址转换后所对应的 物理地址是不一样的。所以两个进城中的这两个地址相互之间没有任何关系。
fork时子进程获得父进程数据空间、堆和栈的复制,所以变量的地址(当然是虚拟地址)也是一样的。
每个进程都有自己的虚拟地址空间,不同进程的相同的虚拟地址显然可以对应不同的物理地址。因此地址相同(虚拟地址)而值不同没什么奇怪。
具体过程是这样的:
fork子进程完全复制父进程的栈空间,也复制了页表,但没有复制物理页面,所以这时虚拟地址相同,物理地址也相同,但是会把父子共享的页面标记为“只读”(类似mmap的private的方式),如果父子进程一直对这个页面是同一个页面,知道其中任何一个进程要对共享的页面“写操作”,这时内核会复制一个物理页面给这个进程使用,同时修改页表。而把原来的只读页面标记为“可写”,留给另外一个进程使用。
这就是所谓的“写时复制”。正因为fork采用了这种写时复制的机制,所以fork出来子进程之后,父子进程哪个先调度呢?内核一般会先调度子进程,因为很多情况下子进程是要马上执行exec,会清空栈、堆。。这些和父进程共享的空间,加载新的代码段。。。,这就避免了“写时复制”拷贝共享页面的机会。如果父进程先调度很可能写共享页面,会产生“写时复制”的无用功。所以,一般是子进程先调度滴。
(注1:在理解时,你可以认为fork后,这两个相同的虚拟地址指向的是不同的物理地址,这样方便理解父子进程之间的独立性)
(注2:但实际上,Linux为了提高 fork 的效率,采用了 copy-on-write 技术,fork后,这两个虚拟地址实际上指向相同的物理地址(内存页),只有任何一个进程试图修改这个虚拟地址里的内容前,两个虚拟地址才会指向不同的物理地址(新的物理地址的内容从原物理地址中复制得到))
wait和exit
进程间通信必须要借助内核(无论管道、消息队列、还是共享内存等进程间通信形式),子进程的返回值肯定是先交给内核,然后父进程向内核要子进程的返回值。父进程调用pid_t wait(int *status)后,内核就把子进程的返回值存储到status指向的内存空间。子进程的返回值存放在它的PCB中,调用exit后内核会把进程占用的大部分资源回收,比如内存、页表等,但不能回收PCB,需要将其中的返回值交给父进程后才能回收。
exit调用表面上是结束子进程运行并传递返回值给内核,本质上是内核在幕后将进程除了PCB以外的所有资源回收。
孤儿进程
父进程提前退出,父进程的子进程会称为孤儿进程,被init进程收养
僵尸进程
僵尸进程就是没有父进程来给某进程收尸,也就是调用wait收取返回值,因此其PCB一直不能被回收。
管道
Linux中管道实现如下图:

其实就是对一页框大小的内存区域做读写操作
匿名管道:在内核中,父子进程因为有相同的管道描述符,所以都可以访问这个管道。
有名管道:在文件系统中创建一个管道文件(FIFO,是一种特殊的文件类型),使得该管道对任何进程都可见,因此没有父子关系也能通信。当一个进程以读(r)的方式打开该文件,而另一个进程以写(w)的方式打开该文件,那么内核就会在这两个进程之间建立管道,所以FIFO实际上也由内核管理,不与硬盘打交道。
Linux共享内存,信号
http://blog.csdn.net/lqygame/article/details/71424917
http://blog.csdn.net/lqygame/article/details/73555430

写在最后
每天晚上看一点,历时接近1个月终于把这本书读完,感谢钢哥,这本书刷新了我对操作系统的认知,总算对操作系统有了个很全面的了解。这些笔记是针对我自己的一些感觉需要记录下来的东西,OS还需要学习的东西还有很多啊。
---------------------  
作者:月黑风高云游诗人  
来源:CSDN  
原文:https://blog.csdn.net/lqygame/article/details/73850249  
版权声明:本文为博主原创文章,转载请附上博文链接!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/439779.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Apollo进阶课程㊱丨Apollo ROS深入介绍

原文链接:进阶课程㊱丨Apollo ROS深入介绍 ROS是一个强大而灵活的机器人编程框架,从软件构架的角度说,它是一种基于消息传递通信的分布式多进程框架。ROS本身是基于消息机制的,可以根据功能把软件拆分成为各个模块,每…

一步步编写操作系统 31 cpu的分支预测 下

让我们说说预测的算法吧。 对于无条件跳转,没啥可犹豫的,直接跳过去就是了。所谓的预测是针对有条件跳转来说的,因为不知道条件成不成立。最简单的统计是根据上一次跳转的结果来预测本次,如果上一次跳转啦,这一次也预…

Apollo进阶课程㊲丨Apollo自动驾驶架构介绍

原文链接:进阶课程㊲丨Apollo自动驾驶架构介绍 自动驾驶硬件架构:一般采用激光雷达作为主要感知传感器,同时结合摄像头、GPS/IMU、毫米波雷达、超声波雷达等,以NVIDIA Drive PX2 或 Xavier作为主要计算平台,在工业PC机…

Apollo进阶课程㊳丨Apollo平台的快速入门

原文链接:进阶课程㊳丨Apollo平台的快速入门 Apollo是向汽车行业及自动驾驶领域的合作伙伴提供一个开放、完整、安全的软件平台,帮助他们结合车辆和硬件系统,快速搭建一套属于自己的完整的自动驾驶系统。 上周阿波君为大家详细介绍了「进阶课…

一步步编写操作系统 33 利用bios中断0x15子功能0xe820获取内存

咱们先介绍0xE820子功能,这是最灵活的内存获取方式。 bios中断 0x15的子功能0xE820能够获取系统的内存布局,由于系统内存各部分的类型属性不同,bios就按照类型属性来划分这片系统内存,所以这种查询则呈迭代式,每次bio…

16.深度学习练习:Building your Recurrent Neural Network - Step by Step

本文节选自吴恩达老师《深度学习专项课程》编程作业,在此表示感谢。课程链接:https://www.deeplearning.ai/deep-learning-specialization/Building your Recurrent Neural Network - Step by Step1 - Forward propagation for the basic Recurrent Neur…

【2019icpc徐州站】Random Access Iterator(概率dp,有坑,tricks)

题干: Recently Kumiko learns to use containers in C standard template library. She likes to use the std::vector very much. It is very convenient for her to do operations like an ordinary array. However, she is concerned about the random-access…

一步步编写操作系统 34 内核利用bios中断获取物理内存大小

接上文,另一个获取内存容量的方法是bios 0x15中断的子功能0xE801。 此方法虽然简单,但功能也不强大,最大只能识别4G内存,不过这对咱们32位地址总线足够了。稍微有点不便的是,此方法检测到的内存是分别存放到两组寄存器…

17.深度学习练习:Character level language model - Dinosaurus land

本文节选自吴恩达老师《深度学习专项课程》编程作业,在此表示感谢。 课程链接:https://www.deeplearning.ai/deep-learning-specialization/ 文章目录1 - Problem Statement1.1 - Dataset and Preprocessing1.2 - Overview of the model2 - Building blo…

Apollo进阶课程㊴丨Apollo安装过程概述

原文链接:进阶课程㊴丨Apollo安装过程概述 Apollo是一个自动驾驶的平台,推荐的参考运行环境为:ThinkPAD X240、CPU:i5 、四核 、内存 8G、 硬盘容量40G以上。 上周阿波君为大家详细介绍了「进阶课程㊳丨Apollo平台的快速入门」。 …

UML类图关系(泛化 、继承、实现、依赖、关联、聚合、组合)

继承、实现、依赖、关联、聚合、组合的联系与区别 分别介绍这几种关系: 继承 指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力,继…

CS231n(1):图片分类笔记与KNN编程作业

声明:本博客笔记部分为CS231n官网笔记,这里对其进行引用,在此表示感谢。 课程官网地址为:http://vision.stanford.edu/teaching/cs231n/syllabus.html 本次课程对应B站教学视频为: https://www.bilibili.com/video/av5…

【HDU - 6557】Justice(思维,模拟,套路,SETset)

题干: On the table there are n weights. On the body of the i-th weight carved a positive integer kiki , indicating that its weight is 12ki12ki gram. Is it possible to divide the n weights into two groups and make sure that the sum of the weight…

Apollo进阶课程㊵丨Azure仿真平台使用

原文链接:进阶课程㊵丨Azure仿真平台使用 Azure是一种灵活和支持互操作的平台,它可以被用来创建云中运行的应用或者通过基于云的特性来加强现有应用。它开放式的架构给开发者提供了Web应用、互联设备的应用、个人电脑、服务器、或者提供最优在线复杂解决…

java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一

对java的泛型特性的了解仅限于表面的浅浅一层,直到在学习设计模式时发现有不了解的用法,才想起详细的记录一下。本文参考java 泛型详解、Java中的泛型方法、 java泛型详解 1. 概述 泛型在java中有很重要的地位,在面向对象编程及各种设计模式…

动手学无人驾驶(3):基于激光雷达3D多目标追踪

上一篇博客介绍了无人驾驶中的车辆检测算法(YOLO模型),该检测是基于图像进行的2D目标检测。在无人驾驶环境感知传感器中还有另一种重要的传感器:激光雷达。今天就介绍一篇无人驾驶中基于激光雷达目标检测的3D多目标追踪论文&#…

换种方法学操作系统,轻松入门Linux内核

计算机已成为现代人日常工作、学习和生活中必不可少的工具。操作系统是计算机之魂,作为用户使用计算机的接口,它负责调度执行各个用户程序,使计算机完成特定的任务;作为计算机硬件资源的管理者,它负责协调计算机中各类…

Apollo进阶课程㊶丨Apollo实战——本机演示实战

原文链接:进阶课程㊶丨Apollo实战——本机演示实战 Apollo是一个开放的、完整的、安全的平台,将帮助汽车行业及自动驾驶领域的合作伙伴结合车辆和硬件系统,快速搭建一套属于自己的自动驾驶系统。 上周阿波君为大家详细介绍了「进阶课程㊵丨A…

java常见异常类图(分类了Error/RuntimeExecption、check Exception)

Error:表示由JVM所侦测到的无法预期的错误,由于这是属于JVM层次的严重错误,导致JVM无法继续执行,因此,这是不可捕捉到的,无法采取任何恢复的操作,顶多只能显示错误信息。Exception:表…

Apollo进阶课程㊷丨Apollo实战——车辆与循迹驾驶能力实战

原文链接:进阶课程㊷丨Apollo实战——车辆与循迹驾驶能力实战 循迹自动驾驶是指让车辆按照录制好的轨迹线进行自动驾驶,其涉及到自动驾驶中最基本的底盘线控能力、定位能力、控制能力,是自动驾驶系统的一个最小子集。 上周阿波君为大家详细介…