这八章讲述了xv6的文件系统,这个文件系统的实现很简单,有许多可以优化的地方,但也有很多复杂的地方。从磁盘组织、缓存、日志、Inode、目录、文件名与文件描述符。其实可以简单分为三部分:
- 底层存储(磁盘组织、磁盘缓存、Inode、Directory)
- 持久层(日志事务)
- 用户层(文件名、文件描述符)
这八章讲述了xv6的文件系统,这个文件系统的实现很简单,有许多可以优化的地方,但也有很多复杂的地方。从磁盘组织、缓存、日志、Inode、目录、文件名与文件描述符。其实可以简单分为三部分:
lab9以提高并行度的方式熟悉并行编程,第一个实验是多核并行,第二个实验是key级别的哈希表锁编程。
这个实验主要是熟悉多线程编程,比较容易。
第一个实验线程切换,这个只要理解xv6的线程调度就能解决,甚至代码都可以直接抄。
第二个实验哈希表加锁。关键代码量不到两行,甚至分桶加锁也是。
第三个实验同步屏障,这个还有意思一点。
第七章讲述了xv6中线程调度的机制,核心就是swtch函数以及调度器内核线程。在线程调度的基础上,讲述了线程同步的一个机制:sleep&wakeup(其实就是条件变量)。有了同步机制后,继续展开讲进程退出、资源回收等知识。fork+exec+wait 一套流程。
第六章主要是讲并发编程,为什么要用锁、什么时候使用锁、锁范围、加锁顺序、死锁、可重入锁等知识,还介绍了xv6中自旋锁的实现。
特别要注意xv6中持有锁就不允许中断;内存屏障用于避免指令重排,这些都是锁实现的细节。
本节融合了lec13的内容,总体上属于并发编程入门,信号量、条件变量等多进程同步机制没有介绍,后续章节会涉及。
MIT6.S081 lab5 lazy allocation
lab5是关于懒分配的实验。前言讲得很好,One of the many neat tricks an O/S can play with page table hardware is lazy allocation of user-space heap memory. LA是用户堆空间上的Trick。
Xv6 applications ask the kernel for heap memory using the sbrk() system call. 利用sbrk系统调用来增长或减少堆空间。
LA的原因,程序角度:
内核角度:
因此更好的做法是 That is, sbrk() doesn’t allocate physical memory, but just remembers which user addresses are allocated and marks those addresses as invalid in the user page table. When the process first tries to use any given page of lazily-allocated memory, the CPU generates a page fault, which the kernel handles by allocating physical memory, zeroing it, and mapping it
第五章主要讲述的是外部设备的中断,不同于软件中断,外部设备中断可以与CPU处理并行。
这里要特别理解外设的驱动,驱动的top部分一般是驱动提供给用户的接口服务,驱动的bottom部分则是interrupt handler。top部分和bottom部分通过buffer解藕,top部分往设备的缓冲区读写完事儿,待设备处理完成发送一个中断,bottom部分则处理中断,bottom亦能读写缓冲区。
值得注意的是:一个中断是如何产生,又如何被CPU处理的(这里会有多个CPU);设备与CPU的并行。
这节融合了lec09的内容,通过追踪以下两个场景来分析中断过程:
console中的提示符“$ ” 是如何显示出来的;
如果你在键盘输入“ls”,这些字符是怎么最终在console中显示出来的。
第四章的主题是陷阱与系统调用。关键问题:系统调用是怎么从用户态切换到内核态的?
从中断角度看,系统调用是一软中断,发生中断后由中断向量处理,其中中断向量的地址又在寄存器stvec上。
这里融合了lec06的内容 和lec08的内容,lec08讲述了page fault中断处理的妙用,核心思想都是懒分配:给你虚拟页但不实际分配物理页,等到实际要用时再分配。
第三章的主题是页表,单看页表会很抽象,但页表背后的思想是地址空间的隔离。让每个进程都有自己的地址空间,保护地址空间不受他人侵犯。同时,页表管理的“页”,页内地址连续,以页为单位,避免页表过于庞大(多级页表也是为了实现这个目标)。同时,虚拟空间到物理空间的映射,多了几分实用trick,比如内核采用直接映射、内核页表下的guard page(未映射)、内核和用户相同的映射(trampoline page,多对一映射)。
本节融合了课程lec04的内容。虚拟地址的抽象是为了程序的隔离性,理解这点后就很容易了。
第二章以操作系统三个要求:复用、隔离和交互展开讲述了内核设计、进程设计,还描述了xv6的启动流程。
看完这一章还是很笼统抽象,一些细节还是需要等到后续披露,但这时候你大致把握到操作系统的整体设计了。
隔离的设计——用户态与内核态;复用的设计——用户进程;交互设计——进程通信。