版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
前言操作系统是一种简洁的系统软件。本书通过介绍操作系统的根本概念和原理,并结合操作系统原理来分析一个小型但全面的操作系统xv6,并进一步进展各种基于xv6操作系统的试验,来让读者了解和把握操作系统的设计与实现。xv6x86架构的计算机系统上UNIX的教学用操作系统。xv6起源于MIT2023年秋季,FransKaashoek,JoshCates,andEmilSitMIT开设了一门的试验型课程“操作系统工程”,英文名称是“OperatingSystemsEngineering”,课程代号是“6.097”,后改为“6.828”,在此课程上,一开头承受了“莱昂UNIX源代码分析”〔英文书名是“Lion”CornmentaryonUNIX6thEditionWithSourceCode”〕UNIXv6〔V6〕PDP-11计算机系统上。为了让学生更好地理解V6的实现,FransKaashoek等从2023年夏季开头,参考V6的架构,x86计算机系统上重实现了一个支持多处理器计算机系统的类似UNIX的教学用操作系统,xv6MIT本科生课程“6.828:OperatingSystemsEngineering中,xv6主要exokernelJOSxv6MIT的网址在“:///6.828/xv6/“:///6.828/xv6/第零章安装使用LinuxFUbuntuLinuxUbuntuLinux下编程。编译[needupdate]UbuntuLinux8.10Capt工具进一步安装相关软件包$sudoapt-getinstallgccbinutilslibc6-devgdbxv6软件包,到某一名目,然后到此名目下执行$make就可以生成相关执行文件和镜像,包括xv6.img(bootloaderxv6kernel)fs.img(包含应用程序)运行[needupdate]UbuntuLinux8.10apt工具进一步安装相关软件包$sudoapt-getinstallqemubochsbiosvgabioslibsdl1.2debiankvmqemu执行,可执行如下命令qemu-smp4-parallelstdio-hdbfs.img-hdaxv6.imgkvm执行,可执行如下命令kvm-smp4-parallelstdio-hdbfs.imgxv6.imgqemukvmB。调试[needupdate]qemuqemudebugger调试〔patch并qemuC源码级调试〕和gdb远程调试〔C源码级调试,缺点是可能会有惊异的问题,对硬件把握不够。gdb远程调试的方法如下:aqemu调试方式启动qemu-S-s -smp2-monitorstdio-hdbfs.img-hdaxv6.imgbgdb启动并调试gdbkernel(gdb)targetremote:1234(gdb)breakFUNCTION-NAME(gdb)continue...(gdb)quitqemuinternaldebugger调试aqemu启动命令qemu-smp2-monitorstdio-hdbfs.img-hdaxv6.imgqemu的monitor中可执行如下命令进展调试分析x/fmtaddr--virtualmemorydumpstartingat”addr”infocpus--showinfosforeachCPUinforegisters--showthecpuregisterssinglestepsinglestap_enabled--togglesinglestepmodebreakpoint_insertaddr--insertbreakpointbreakpoint_removeaddr--removebreakpointbreakpoint_show--showbreakpointwatchpoint_insertaddrtype--insertwatchpointtype0=read1=writewatchpoint_removeaddr--removewatchpointwatchpoint_show--showwatchpointwhere--showcallsstack第一章总体构造和系统组成本章将给出xv6启动实现的概貌。读者将学习以下一些内容:操作系统是什么?xv6是如何产生的?xv6的总体构造是什么?xv6包含哪些重要的组成局部?操作系统是一种软件,操作系统没有一个准确和统一的定义。操作系统是一种比较简洁的软件,我们可以从多种角度来了解操作系统。从操作系统的任务来看,操作系统的任务主要是把握和治理计算机系统中的硬件资源并对应用软件和用户供给各种便利使用计算机的功能。通过操作系统,能有效地组织和治理计算机系统中的硬件资源和其他软件资源,向用户和应用软件供给各种效劳功能,使得用户和应用软件能够灵敏、便利、有效地使用计算机,并使整个计算机系统能高效地运行。从操作系统在计算机系统中的实现层次上看,操作系统位于计算机硬件之上,应用软件之下。由于操作系统是一个简洁的软件系统,为了能够更好地设计和实现操作系统,我们可以从功能上对操作系统进展分解,可把操作系统分解为系统调用、进程调度、内存治理、中断处理、文件系统和设备治理等功能模块,在具体实现上可承受模块化、层次化和面对对象等设计方法来设计实现操作系统。OS组成构造图[needtoupdate]。要了解xv6,首先我们需要了解操作系统的一些根本概念(请参考A)xv6〔xv6-rev2版本〕是一个支持对称多处理器(SMP)的类Unix系统。它包含操作系统一些最根本的要素,包括系统调用、进程调度、内存治理、中断处理和文件系统等。xv6xv6UNIX操作系统设计思路。简洁地说,xv6基于扁平内存治理的层次型单体内核,应用程序和操作系统是处于不同的特权状态和地址空间。代表应用程序的用户态进程运行在CPU的用户态〔又称非特权模式,用户模式,无法直接访问系统硬件和操作系统中的系统数据,而操作系统运行在CPU的核心态〔又称特权模式,内核模式,可以访问系统硬件和核心数据。下面分别从系统调用接口、进程/文件系统、I/O系统调用是应用程序访问操作系统的接口。在系统调用接口上,通用操作系统与基于此操作系统的应用程序处于两个不同的CPU特权态,操作系统处于核心态,而应用程序处于用户态。在核心态可以执行CPU特权指令,而用户态无法执行特权指令,且只能通过特定的指令或中断来访问操作系统供给的各种功能。这在确定程度上保证了系统整体的安全,避开应用程序对操作系统可能的破坏。在内存治理方面,通用操作系统承受了虚拟内存治理方式,这样可以让内存需求超过实际物理内存的进程/线程能够执行,其主要思想是把重要和常用的数据和执行代码放在物理内存中,把不常用的数据和执行代码放到二级存储〔这里主要指的是硬盘等可在掉电后保存数据的存储介质同内存区域的保护,不同进程之间,或者应用程序和操作系统之间的地址空间相对隔离。这样一般状况下不同进程的地址空间不能直接访问,且应用程序不能直接访问内核地址空间。所以一个与错误的应用程序不会导致系统的崩溃,从而增加了系统的牢靠性。xv6操作系统没有承受X86段模式的单一地址空间治理方式。在内存安排和释放的治理上,xv6相对实现得比较简洁,承受基于可变分区安排的首次适配算法,简洁产生内存碎片。在进程/线程治理方面,当前通用操作系统结合虚存治理,承受进程和线程结合的治理方式。进程代表了一个程序执行的过程以及其所占用的计算机资源〔包括CPU、内存、文件等,进程的执行流可用线程来表示。操作系统的调度单位可以是进程或线程。一个进程可以包含多个线程,属于同一进程的多个线程共享进程治理的资源,比方属于同一进程的多个线程共享进程所治理的内存,这样这些线程可以直接访问属于进程的全局地址空间。xv6操作系统实现了一个基于进程〔没有实现线程〕的简洁进程治理机制。在文件系统治理方面,当前通用操作系统结合虚存治理,实现了多种简洁、高效且牢靠的文件系统,且建立了一个统一的虚拟文件系统层,屏蔽不同文件系统的差异,对上层供给统一的接口。且与用户治理和进程治理结合,可实现安全治理,保证对文件的安全访问。xv6操作系统inode索引方式的文件系统。在I/O治理方面,xv6操作系统与通用操作系统〔特别是类UNIX操作系统〕差异不是特别大,都把设备“看成”是一种特别的设备文件,有设备号,用文件的访问接口来进展翻开、关闭、读、写和把握等操作。在灵敏性方面,xv6驱动程序不能象通用操作系统那样依据硬件状况动态加载,而是在编译时候就静态确定的。xv6总体架构从操作系统模型上来看,xv6是一个单地址空间的层次式单体内核,不是微内核〔microkernel〕模型的操作系统〔如Mach,QNX,与通用操作系统〔如Linux〕空间和特权模式上也有确定的差异。下面主要分进程调度、内存治理、同步互斥、文件系统几xv6进展介绍。同步互斥SMPCPU中都是共享的,所以在需要某xv6spinlock,从而可以对共享CPU数量。内存治理在内存治理方面,xv6承受了段式虚拟内存的治理方式。每个用户进程所占用的内存都是在一个连续的段中。用户进程内存的分布为:代码段、静态变量段、固定大小的栈和可变大小的堆空间。由于进程内存是依据段治理的,因此在每次安排进程内存时,xv6进程治理SMPCPU执行CPUCPU的操作系统治理问题,具体包括假设创立进程、如何删除进程、选择哪个进程占用哪个CPU,何时进展进程切换,进程能够持续占用CPU的时间片段的大小设定等。在xv6中,首先其进程是基于时间片来调度的。每次进程的调度是由时钟中断产生的,或者是因当CPU之间都共享一个进程池〔具体实现为一个全局数组,其中有全部待运行的进程。在每个时间片中,CPU文件系统xv6中供给了一个简洁的文件系统,这个文件系统供给了大多数POSIX标准的接口。由于这个文件系统比较简洁,其中一个文件最多由(12+128)也被限制在(12+128)*512Bytes。在这个文件系统中供给了一个Buf层,用来缓存磁盘上的数据。但是此文件系统是写直达的,因此每次更都会直接写到磁盘上。中断治理和系统调用治理[NTU]外设治理[NTU](boot)概述本章将给出xv6启动实现的概貌。读者将学习以下一些内容:bootloader是什么?bootloader做了哪些事情?xv6是如何被加载并启动的?xv6的初始内存治理是如何实现的?xv6的初始中断治理是如何实现的?xv6如何实现内核态到用户态的转变的?xv6启动用户态进程前需要完成哪些事情?xv6如何创立并启动第一个用户态进程?当计算机加电后,一般不直接执行操作系统,而是执行引导加载程序。简洁地说,引导加载程序就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立系统的内存空间映射图,从而将系统的软硬件环境带到一个适宜的状态,以便为最终调用操作系统内核预备好正确的环境。最终引导加载程序把操作系统内核映像加载到RAM中,并将系统把握权传递给它。对于绝大多数计算机系统而言,操作系统和应用软件是存放在磁盘〔硬盘/软盘、光盘、EPROM、ROM、Flash等可在掉电后连续保存数据的存储介质上。计算机启动后,CPU一开头会到一个特定的地址开头执行指令,这个特定的地址存放了系统软件〔不仅是操作系统,还可能是引导加载程序等。引导加载程序(bootloader)PC386PCBIOS(BasicInputOutputSystem,即根本输入/输出系统,其本质Flash/CMOS上的软件)和位于软盘/OSBootLoader一起组成。BIOS实际上是被固化在计算机ROM〔只读存储器〕芯片上的一个特别的软件,为上层软件BIOS就是PC计算机硬件与上层软件程序之间的一个“桥梁“,负责访问和把握硬件。以PC386为例,计算机加电后,CPU从物理地址0xFFFFFFF0〔由初始化的CS:EIP确定,此时CSIP0xF0000xFFF0)〕开头执行。在0xFFFFFFF0这里只是存放了一条跳转指令,通过跳转指令跳到BIOS例行程序起始点。BIOS做完计算机硬件自检和初始化后,会选择一个启动设备〔例如软盘、硬盘、光盘等个特定的地址0x7c00处,然后CPU把握权会转移到那个地址连续执行。至此BIOS的初始化工作xv6。xv6系统的启动流程大致是这样的:做为多处理系统,启动是首先从一个CPU的启动CPUBIOSOSBootLoader从磁盘上〔一般是位于第一个扇区〕拷贝到内存当中。当BIOSBootLoaderBootLoaderCPUCPU将把启动代码拷贝到内存中,然后唤起其他CPU执行这一段代码,完成它们的初始化过程。xv6的源码中,整个启动过程主要牵涉到如下几个文件:bootloaderbootasm.Sbootmain.cxv6初始化模块main.cbootother.S下面将针对这些文件进展分析,对启动过程分成两局部进展介绍。代码分析bootloader代码分析bootloader的组成makefile50行~56行有如下语句50: bootblock:bootasm.Sbootmain.c51: $(CC)$(CFLAGS)-O-nostdinc-I.-cbootmain.c52: $(CC)$(CFLAGS)-nostdinc-I.-cbootasm.S53: -N-estart-Ttext0x7C00-obootblock.obootasm.obootmain.o54: $(OBJDUMP)-Sbootblock.o>bootblock.asm55: $(OBJCOPY)-S-Obinarybootblock.obootblock56: ./sign.plbootblockbootloader包含两个文件,bootasm.Sbootmain.c。生成的bootloader会写到一个主引导扇区上面。作为主引导扇区,其位置在软盘或硬盘的第一个扇区,其大小为512个字节,在此扇区的最终两个字节是一个主引导扇区特征码为”55AA”。Makefile的51行和52gccbootmain.cbootasm.Sbootmain.obootasm.o。Makefile53ldbootmain.obootasm.o链接成目标文件bootblock.o,且定义了起始执行的点〔也称入口点〕为start函数,具体的代码段起始地址为0x7C00[Q]大家还0x7C00这个特别的地址的含义吗?Makefile54行是通过objdumpbootblock.obootlock.asm。Makefile55objcopy程序把bootblock.o变成二进制码bootlock。[Q]bootlock的大小可以大于512字节吗?Makefile的56sign.pl程序把bootlock512个字节,并把最终两个字节写成”55AA”。[小试验]xv6.img512个字节取出来,反汇编它的内容,并与bootasm.S和bootmain.c的内容〔bootblock.asm〕进展比较,512个字节的最终两个字节的内容是否是“55AA”代码分析bootloader的启动主要涉及到bootasm.S、bootmain.c。其中bootasm.S的主要作用是从实模bootmain的作用是把内核从磁盘拷贝到内存中。bootasm.S在进入实模式向保护模式切换之前,首先需要把中断关闭(“cli“atline15),保证转换过程不被硬件中断打断。19~22DS,ES,SS进展清零。20~42(A20地址线)[历史]在8086年月,8086供给了20跟地址线,那么供给的可寻址空间范围即0~2^20(00000H~FFFFFH)的1M8086的数据处理位宽位16位,8086供给了段地址加偏移地址的地址转换机制,就是我们常见的”段地址:偏移地址(或有效地址)”,实际的计算方法为:”段地址*10H+偏移地址”,作为段地址的数据是放在段存放器中的(16位),而座位偏移地址的数据则是通过8086供给的寻址方式来计算而来的(16位)。而“段值:偏移”这种表示法能够表示的最大内存为10FFEEh(FFFF0 + FFFF),所以当寻址到超过1MB的内存时,会发生“回卷”〔不会发生特别。但是到了80286供给了24根地址线,cpu的寻址范围变为2^24=16M,同时也供给了保护模式,真的可以访问到1MB以上的内存了,此时假设遇到“寻址超过1MB”的状况,系统不会再“回卷”了,这就造成了向上不兼容。为了保持完全的兼容性,IBM打算在PCAT系统上加个规律,来仿照以上的缭绕特征。他们的方法就是把A20和键盘把握器的一个输出进展AND,这样来把握A20的翻开和关闭。一开头时A20是被屏蔽的〔总为0,直到系统软件去翻开它。留意A20而非A20~A31被把握,所以在A20关闭时会发生一些好玩的副作用。就是在访问奇当A20Gate制止时,则程序就像在8086中运行,100000h~100FFEFh的地是不行访问的。A20Gate是要翻开的。为了使能全部地址位的寻址力气当A20Gate制止时,则程序就像在8086中运行,100000h~100FFEFh的地是不行访问的。A20Gate是要翻开的。为了使能全部地址位的寻址力气,必需向键盘把握器8042发送一个命令。键盘把握器8042将会将它的的某个输出引脚的输出置高电平,作为A20门的输入。一旦设置成功之后,内存将不会再被绕回(memorywrapping),这样我们就可以寻址整个286的16M内存,或者是寻址803864G内存了。8042IO0x60~0x6fIBMPC/AT使用的只有0x60和0x64两个端口〔0x61、0x62和0x63用于与XT兼容目的。8042通过这些端口给键盘把握器或键盘发送命令或读取状态。输出端口P2用于特定目的。位0〔P20引脚〕用于实现CPU复位操作,位1〔P21引脚〕用户把握A20信号线的开启与否。系统向输入缓冲〔端口0x64〕写入一个字节,即发送一个键盘把握器命令。可以带一个参数。参数是通过0x60端口发送的。命令的返回值也从端口0x60去读。图Intel8042芯片或其兼容芯片的规律示意图28~31I/O0x64I/O0x641位〔0位〕00x64busy10为止。33~340xd1I/O0x64;0xd1命令是写输出端口,bit0是复位,bit1是GateA20.36~39I/O0x64I/O0x641位〔最低位为第0位〕00x64busy10为止。41~420xdfI/O0x60;0xdfA20至此,A20地址线已经使能。48行,“lgdtgdtdesc“gdtdesc中给出了段表有效大小,和所在地址(gdt)gdt01段是21、2段的范围都是0x0~0xffffffff。在第49~51行中,通过将CR0的第0位置1,把保护模式设置为翻开。但此时段模式并没有55ljmpcs变成$PROT_MODE_CSEG所指向的段〔8>>3=1,gdt1段,即代码段ljmp后,32位模式。59~65gdt2段,即数据段。bootmain.c68行,将栈顶指针指向$start坐在位置即(0x7c00)69bootmain过程,进展内核的加载。bootmain.c在这个文件中主要有四个函数:bootmain、waitdisk、readsect和readseg。其中bootmain是加载内核,其余三个都是对磁盘进展访问的程序。waitdisk、readsectreadsegreadsegoffset处开头countvareadsect以扇区为单位进展的。因此在88行保证va是从一个扇区起始位置开头,因此要对va进展对齐。readsect是对磁盘进展读取,waitdisk等待磁盘的预备过程,一旦磁盘预备好后就可以进展读取了。然后看一下bootmain过程。bootmain的目的是从磁盘中加载内核到内存中,其中内核是以ELF执行文件格式存在磁盘上的。首先将从磁盘读取一页大小(8*512B=4KB)的信息,其中包含了ELF(34~37行。当完成拷贝后,bootmain猎取内核入口程序的地址(见40~41行,然后进入该入口(即main.c中的main函数)。操作系统初始化模块代码分析操作系统初始化模块代码分析操作系统的启动局部包含如下文件main.cbootother.Smain.cmain.c的作用是进展对系统各方面的初始化工作,然后唤起其他CPU的初始化。首先我们看processtablebuffercachePICinterruptcontrollerIOAPICinterruptcontrollerphysicalmemoryallocatortrapvectorsfiletableinodecacheconsoledevice&interruptIDEprocesstablebuffercachePICinterruptcontrollerIOAPICinterruptcontrollerphysicalmemoryallocatortrapvectorsfiletableinodecacheconsoledevice&interruptIDEdevice&interrupttimer〔onlyforuniprocessor〕firstuserprocess这些将在后面的文章具体介绍。在初始话内存、中断表、文件系统、I/O设备等之后,第一个CPUbootothersCPUbootothers之前,第一个用户进程将通过userint进展初始化。在初始化其他AP后,将进入scheduler过程。scheduler过程CPU的进展进程调度的,这将在以后进展争论。bootothersbootstrapCPUCPU进展启动。启动时这样进展的,首先把bootother.S的代码拷贝到0x7000起始的这块内存里。bootother.S然后在0x7000-4、0x7000-8两个内存单元记录下bootother.S中将要进展跳转的内核栈位置以及mpmainCPUbootother.Smpmain过程。在mpmain中,每个CPU将进展中断表和段表的初始化,然后翻开中断进入scheduler过程。bootother.Sbootother.SCPUMakefile5862行:58:bootother:bootother.S59: $(CC)$(CFLAGS)-nostdinc-I.-cbootother.S60: $(LD)$(LDFLAGS)-N-estart-Ttext0x7000-obootother.outbootother.o61: $(OBJCOPY)-S-Obinarybootother.outbootother62: $(OBJDUMP)-Sbootother.o>bootother.asm可以了解到:Makefile59gccbootother.Sbootother.o。Makefile60ldbootother.o进展地址重定位,start,起始地0x7000bootother.out。Makefile61objcopy把bootother.outbootother。Makefile62objdumpbootother.obootother.asm。bootother.S的执行内容格外类似之前的bootasm.S。在这个文件中晚启动的CPU将会进展从实模式到保护模式的转化〔4249行。然后重设段存放器〔5459行kernelmpmain〔61-63行[Q]这个栈的内容是什么?(spinlock)概述本章将给出xv6同步互斥实现的概貌。读者将学习以下一些内容:什么是竞争状态?什么是互斥?什么是同步?[NUD]xv6中的临界区代码是什么?xv6是怎样处理临界区代码的?当两个或多个线程在执行一些关键性的临界区代码时〔如对共享资源的访问们不会相互阻碍?当线程之间存在着某种依存关系时,如何来调整它们的运行次序?当线程经常需要与其它线程进展通信,那么如何依据需要供给有效的通信手段?这实际上需要操作系统供给同步互斥与通信的手段才能解决上述问题。任何为进程所占用的实体都可称为资源。资源可以是CPU、内存,也可以是I/O设备,还可以是一个变量,一个构造或一个数组等。可以被一个以上进程使用的资源叫做共享资源。为了防止数据被任凭访问〔特别是执行写操作这叫做互斥〔mutualexclusion。需要互斥访问的共享资源称为临界资源。假设两个或多个进程对同一共享资源同时进展读写操作,而最终的结果是不行推想的,该结果取决于各个进程具体运行状况。则称此状态为竞争状态〔racecondition问,可能导致竞争状态的消灭。我们把可能消灭竞争态的程序片断称为程序临界区。程序临界区在处理时不行以被中断,要保证其操作的原子性。为确保临界区程序执行过程中不被中断,在进入临界区之前要屏蔽中断,而临界区代码执行完以后要马上使能中断,以削减对中断处理延迟的影响。Spinlock的引入是为了进展资源的互斥访问。在SMP架构下,每个CPU的权限都是一样的,但是某些状况下,一个CPU需要对资源进展独占,此时就可以通过spinlock来进展。spinlockCPUxchg完成的。具体的实现方法如下。2.2.代码分析spinlock.hspinlock构造的定义如下:structspinlock{structspinlock{uintlocked;//Isthelockheld?//Fordebugging:char*name;intlock.cpu;//Nameoflock.//Thenumberofthecpuholdingtheuintpcs[10]; //Thecallstack(anarrayofprogramcounters)//thatlockedthelock.};locked变量,这个用来表示当前锁是否被锁上。其他的变量name,cpu和pcsname记录锁的用途,cpucpu取得了这把锁,pcs记录了获得这把锁时的栈的内容。spinlock.cspinlock.cspinlock的各种操作:初始化、猎取锁,释放锁等。我们依次阅读文件中的每个过程。初始化锁initlockname、lockedcpu三个域。cpu0xffffffff,cpu全部。猎取锁acquire过程是猎取锁(lock)28~29pushcli屏蔽中断,检查当前锁是否CPUcliCPU的中断关闭(CPU的中断并不受到影响,而且其他软中断也并没有被关闭35while将直到成功猎取锁为止。在35cmpxchg去猎取锁。其指令格式为:xchg(va,newvalue)。作用是交换内存地址vanewvaluevaxchglocked=0表示这把xchg(va,1)0whilewhile循环中打转。跳出while表示获得了锁,42CPUID。43getcallerpcs记录获得锁时的函数调用栈。释放锁releaseCPU拿到这把锁,假设不是,则报错;假设是,那CPUCPU已经没有拿popcli将中断翻开。第四章内存治理概述本章将给出xv6内存治理实现的概貌。读者将学习以下一些内容:xv6如何进展内存治理初始化的?xv6的静态内存安排的空间包括什么?xv6的动态内存安排的空间包括什么?xv6的动态内存安排是如何实现的?xv6的动态内存安排的空间?内存治理机制是实时操作系统的重要组成局部。xv6不支持虚拟存储治理,不支持简洁的段页式的保护机制,而承受线性编址方式,即规律地址和物理地址一一对应的平面模式。这样没有虚拟存储治理供给的不受限于物理内存大小的大地址空间、地址保护等功能。xv6同时支持静态内存安排和动态内存安排两种治理方式。静态内存安排是指在编译或链接时将应用所需的内存空间安排好。承受这种安排方案的xv6内核映像所占内存空间〔代码段和数据段等〕的大小一般在编译时就能够确定,中断向量表等其它区域所占用的内存空间大小是个定值。这样承受静态的内存安排机制,在编译时就可以确定xv6而动态内存安排是指系统运行时依据应用需要动态地安排内存。动态内存安排的实现机制灵敏,给程序实现带来极大的便利,有的应用环境中动态内存安排甚至是必不行少的。xv6xv6.img所在内存的末尾开头,增加一块1MB1MBxv6中动态安排和释放。在初始化完动态内存空间后的内存布局如下:代码分析kalloc.c动态内存治理初始化内存空间初始化工作由函数kini完成,执行完kinit后,内存布局如下所示:bootloaderx0x10000mainkalloc.c文件中的kinit函数对内存进展初始化。其执行流程如下:initlockkalloc_lock〔32行〕endstartstart指针startxv6所治理的空闲区域的起始地址〔3334行〕2564Kkfreestart指针指向的地址为256*4*1024〔3537行〕动态内存安排与释放kalloc.ckfree是回收一段内存,而kalloc是安排一段内存。xv6的内存治理是格外简洁的。由于内存安排是以连续的段的方式进展的,通过单链表方式链接空闲的段。因此经过确定时间的安排,空闲空间将由一个个地址不连续的段组成。xv6用freelist将其按起始地址从左至右排列串起来。每次回收时,将回收的段参与段序列中。假设觉察参与段之后能够合并,则将其合并成一个段。当进展安排时,则遍历整个链表,直到找到一个比需求大的段,则将相应的段安排出去。初始化后第一次安排N次安排和释放后第五章进程治理与调度概述本章将给出xv6进程治理实现的概貌。读者将学习以下一些内容:什么是进程?xv6的进程治理数据构造〔进程把握块,PCB〕包含哪些内容?xv6是如何组织进程治理数据构造?xv6如何进展进程治理初始化的?xv6怎样启动多进程的(即需要做哪些初始化工作)?xv6何时进展进程调度?xv6是如何调度进程的〔CPU运行〕?xv6是如何完成进程切换的?xv6如何启动并执行用户态的进程的?进程的概念程序与进程的概念是不行分的。当用户在计算机上运行一个程序时,此程序对应的进程就诞生了,并实际完成各种程序供给的功能,而用户关闭一个程序时,进程也随之终止。程序是为了完成某项任务编排的语句序列,它要告知计算机如何执行,因此程序是需要通过CPU来运行的,且在程序的运行过程中需要占有计算机的各种资源〔比方内存等〕才能运行下去。假设计算机系统在任一时刻限制只有一个程序在运行,则程序在整个运行过程中独占计算机中的全部资源,这样整个程序运行和治理就简洁了。就象在一个家中只住了一个人A,他想看书就到书房去看书,想睡觉就到睡房的床上去睡觉,想看电视就到电视厅看电视,想吃饭就去餐厅吃饭,没人和他抢占资源。但为了提高计算机系统的资源利用率,需要支持多个程序并发执行。这就会带来很多的问题,如资源的共享与竞争,同步与互斥等。比方此人与B成家并有了小孩C,那就是三口之家同时住一套房,当A想去看足球竞赛直播电视节目的时候,假设觉察电视厅已经有B在坐着看连续剧电视节目了,A就得等待或干别的事情。除非A并在另外一个房间看他的球竞赛直播。由于程序是静态的,我们看到的程序是存储在存储介质〔如硬盘、光盘等〕上的,它无法反映出程序执行过程中的动态特性,而且程序在执行过程中会不断申请资源或释放资源,这样让程序作为共享资源的根本单位是不适宜的,所以需要引入一个概念,它能描述程序的执行过程而且可以作为共享资源的根本单位,这个概念就是进程。简洁地说,一个进程是一个具有确定独立功能的程序在一个数据集合上的一次动态执行过程。每个进程都是整个应用的某一局部。操作系统在规律上维护了进程的运行状态信息,即与进程CPU存放器和栈空间〔只有这样才能实现进程切换。操作系统依据当前进程的状况设置进程的状态,并依据进程的状态〔比方优先级〕CPU并运行,这个过程成为调度。进程的状态进程从诞生到死亡要经受假设干个阶段,也会有生老病死。简洁地说,进程有三种状态:就绪、执行、等待。多种缘由可以导致创立一个进程,比方,当操作系统把一个程序从硬盘调入内存后,在开头执行前,操作系统就要为此程序创立一个对应的进程。又比方,一个进程可以自己创立一个子进程,子进程被创立后就是在内存中,处于就绪态,所谓就绪态就是万事具备,只CPUCPU,就可以执行实际的工作了,其状态就变成了执行态;进程在执行中假设需要等待某个资源〔如等硬盘输入数据CPU,且其状态就变为等待态,这时操作系统又会从处于就绪态的另一个进程中选择一个进程占有CPU,则这另一个进程的状态就变成了执行态。当前一个进程所等到数据到来后,处于等待态的前一个进程又被唤醒,并把状态变成为就绪态。xv6中,进程具有多种状态,包括:EMBRO,SLEEPING,RUNNABLE,RUNNINGZOMBIEproc.h文件中:enumproc_state{UNUSED,EMBRYO,SLEEPING,RUNNABLE,RUNNING,ZOMBIE};状态的含义如下:UNUSED:进程未被创立〔即进程把握块空闲〕时的状态;EMBRYO:需要安排一个进程把握块且找到一个处于UNUSED状态的进程把握块时,把此进程把握块状态设置为要使用的状态;SLEEPING:进程由于等待某资源等缘由无法执行,进入睡眠状态,即等待态;RUNNABLE:进程获得了除CPU之外的全部资源,处于可运行状态,即就绪态;RUNNINGCPU,正在运行的状态,即执行态;ZOMBIE:进程完毕的状态5.1〔左〕SMPCPU猎取进程调度的权利是一样的。CPUscheduler里面进展轮询操作,每次从线程池中选择一个RUNNABLE的进程进展运行。直到运行完毕,或一单位时间片完毕,或者进程主动yield或sleep。CPU5.1〔右〕所示。5.1状态转换的过程[即哪些大事促使了状态的转换TODO]进程把握块程序的运行是通过进程表达的,操作系统对进程进展治理和把握,那么操作系统怎么了解到CPU的现场保存在那呢?这实际是通过进程把握快〔ProcessControlBlock,简称PCB。PCB是进程的唯一标志,在PCB感知进程的存在,通过PCBxv6CPU共享一个进程把握块池,即源代码proc.cproc〔即进程把握块〕类:一类是未使用的进程把握块构造,另一类是正在使用的进程把握块构造。每次要创立一个进程时,只需要从进程把握块数组中取得一个未使用进程把握块构造进展相应的处理即可。代码分析构造与变量构造与变量proc.h文件中定义了几个关键的数据构造。其中context是在内核进展上下文切换需要保存的存放器〔定义在proc.h中:structcontext{inteip;intesp;intebx;intecx;intedx;intesi;intedi;intebp;};[Q]eax?proc构造描述了进程运行需要的数据:structproc{char*mem;processmemory(kerneladdress)uintsz;ofprocessmemory(bytes)char*kstack;kernelstackforthisprocessenumproc_statestate;intpid;ProcessID
//Processstate
//Startof//Size//Bottomof//structproc*parent;void*chan;zero,sleepingonchanintkilled;Ifnon-zero,havebeenkilledstructfile*ofile[NOFILE];structinode*cwd;structcontextcontext;structtrapframe*tf;interruptcharname[16];(debugging)};
//Parentprocess//Ifnon-////Openfiles//Currentdirectory//Switchheretorunprocess//Trapframeforcurrent//Processname其中:其中:memmem记录了进程在内核的起始地址;sz是记录进程所占有的内存空间大小;kstack是进程在内核态的栈;state是进程的状态;pidID;chanNULL时,是进程睡眠时所挂的睡眠队列;killed0时,表示进程被杀死了;ofile数组是进程翻开的文件数组;cwd是进程运行时所处的当前名目;context是切换进程需要维护的硬件存放器内容;tf是中断进程后,需要恢复进程连续执行所保存的存放器内容;name保存了进程的名字〔用于调试。进程在内存中的布局如下:expandableheapexpandableheap〔堆〕fixed-sizestack〔栈〕originaldataandbss〔数据〕Text〔代码〕proc[NPROC]数组〔proc.c11行〕xv6所能够支持的进程所需的相关数据,NPROCxv6可支持进程个数。cpuCPU的相关信息:structcpu{ucharapicid;LocalAPICIDstructproc*curproc;running.structcontextcontext;schedulerstructtaskstatets;tofindstackforinterrupt////Processcurrently//Switchheretoenter//Usedbyx86structsegdescgdt[NSEGS];volatileuintbooted;started?intncli;//Depthofpushcliintena;//x86globaldescriptortable//HastheCPU//Wereinterruptsenabledbeforepushcli?};其中:apicidCPUid编号;curprocCPU上运行的进程把握块;context[] ;ts是Taskstatesegment,用于在中断时找到栈[] ;gdt是此CPU的全局描述符表〔GDT;bootedCPU已经启动了;nclipushcli函数的次数;intena表示[] ;全局变量进程数组proc[NPROC]数组就是进程池。进程池访问锁proc_table_lockspinlock是用来保护对进程池的临界区访问。当前运行进程curproccpu当前运行的进程。第一个进程initproc是记录第一个创立的进程。这个进程格外特别,它将托管全部没有父进程的进程〔也就是父进程先于子进程完毕。下一进程号nextid是用来产生进程号的,在系统启动后会始终保持递增。处理过程与进程相关的处理函数集中在proc.c中,下面将依次介绍相关处理过程。进程治理初始化pinitproc_table_lock锁。初始化用户进程inituserinit是初始化第一个用户进程init。其处理过程如下所示:156copyproccopyproc0,这表示是第一个用户进程。由于是第一个进程,因此在copyproc中没有进展内存等相关构造的初始化;156~173是对相关构造〔包括内存、当前名目cwd、trapframe〕进展初始化。留意的是,161~162行将进程的段加上了用户态权限而不是内核态权限;p->tf->eip=0表0地址。p->tf->esp=p->sz的含义是174~176行是将第一个用户进程的代码〔initcode.S〕拷贝到进程的内存中,然后把进程名字指定为“initcoe设置进程状态为RUNNABLE;178pinitproc。创立子进程在xv6中,可以通过sys_fork来复制父进程内容并创立一个的子进程。其处理过程如下所示:11copyproc函数创立一个的进程,留意这里调用copyproc函数的参数是p,p的相关内容来创立子进程;把创立的子进程状态设置为RUNNABLE,返回子进程的pid。留意这也是fork返回后,确定是父进程还是子进程返回的一个标志。复制进程copyprocsys_forkcopyproc函数,完成对userinitcopyproc函数,完成对第一个用户态进程的创立。其处理过程如下所示:108~109PCB复制;112~115np开拓内核栈空间;116行是将其trapframe所占的空间放在内核栈栈顶,大小位sizeof(structtrapframe),np->tf指向栈顶-sizeof(structtrapframe)的位置;p〔即父进程〕非空,119~121npparentpp中的状态复制到nptrapframe中;p〔即父进程〕非空,124psz〔进程空间大小〕npmem内存空间;p〔即父进程〕非空,131pmemnpmem;p〔即父进程〕非空,133~135filedup函数复制父进程翻开的文件给子进np;p〔即父进程〕非空,136idupnp;139~142shedulereipforkretscheduler中加上的锁给释放。esp指向安排的栈地址;144~145fork产生的,因此其作为子进程0。进程构造的空间安排allocproc是进展进程安排,也就是在进程池中找出一个状态为UNUSED的进程返回。选出来EMBRYOproc_table_lock。增加进程的地址空间growprocsbrk调用。xv6的内存治理格外简洁。当要增大n时,假设原内存空间为sz,xv6将首先尝试开拓一个为sz+n的空间(55~57行)。假设(58~63行)。设置内核空间和用户空间段描述符setupsegstaskstatep0时,IDLE进程,只运行在内核态,并且是在初始化生成的。因此对于这个进程不TSesp00xffffffff81~85CPU设置段描述符,TSS87~88为用户端,段的基址和大小由当前进程打算。设置完成后,lgdtltr进展加载。调度进程scheduler对每个CPU进展进程调度。CPU到没有运行用户进程时,就会进入这个过程中。这个过程不停的从进程中选出一个RUNNABLE的进程,然后运行这个进程〔通过swtch.S中的swtch函数进展。[TODO]schedschedulerswtch进展上下文切换即可。CPUyield是用户进程用来主动放弃当前CPUschedulerscheduler需要加锁所proc_table_lock加上。设置用户进程返回forkretforksys_fork创立的进程是通过shcedulerproc_table_lock锁释放。睡眠进程sleep功能是让进程休眠。首先获得proc_table_lockchan,也就是说只有相关的chanschedchan等记录清proc_table_locklk锁。唤醒进程wakeup功能是唤醒进程。先猎取proc_table_lock,然后调用函数wakeup1,然后释放proc_table_lock。wakeup1chanSLEEPINGRUNNABLE。杀死进程killIDkilled状态置1即可。假设目标进程出于sleeping状态则将其设置成RUNNABLE使其尽早被杀掉。退出进程exit的是用于用户进程退出。在退出之前,用户进程需要关闭翻开的文件(351~356行,将翻开的文件夹关闭(358~359)wait状态。并将其子进程托管init。然后转变其状态为ZOMBIE〔等待父进程进展回收schedCPU。等待进程完毕wait是用于父进程等待子进程完毕只用的。做法是不断的循环知道找到一个子进程变成ZOMBIE状态,则释放ZOMBIE子进程〔回收其资源,然后完毕循环返回其子进程的进程ID在循环的时候需要推断是否被外部进程Kill,或有无活泼子进程,假设被杀死或无活泼子进程,则推出循环。进程上下文切换在操作系统中通常也把上下文切换称为进程切换〔processswitch。当操作系统打算运行另外的进程时,它需要保存当前正在运行进程的当前上下文〔Context,也可称“运行状态信息”,即CPU存放器中的全部内容。这些内容保存在进程的堆栈空间或特定的上下文保存区。完成保存工作后,操作系统就可以把下一个将要运行进程的当前上下文从该进程的栈或上下文CPU一般有两种状况的上下文切换:高优先级的进程由于需要某种临界资源,主动恳求堵塞,让出处理器,此时将调度就绪状态的低优先级进程获得执行。这种切换称为进程级的上下文切换。进程由于时钟中断或其它中断到来而被打断,在中断效劳例程处理完毕后,内核觉察有更高优先级进程处于就绪态,则在中断处理完毕后直接切换到高优先级进程执行。这种调度也称为中断级的上下文切换。swtch.S这个程序是进展上下文切换。9oldcontext11~18行将当前的context存入。留意:eipnewcontext的指针,将全部存放器复原,然后将要运行的eip压入栈,利用ret切换到的进程。留意,在切换回去后,的进程仍处于内核态。(trap&systemcall)概述本章将给出xv6中断处理和系统调用实现的概貌。读者将学习以下一些内容:什么是中断?什么是系统调用?中断与系统调用有何关系?xv6如何处理中断?xv6的时钟中断处理有何特别的作用?xv6的各种实现功能?xv6如何处理系统调用?操作系统需要对计算机系统中的各种外设进展治理,这就需要CPU和外设能够相互通信才行。一般外设的速度远慢于CPU的速度。假设让操作系统通过CPU“主动关心”外设的大事,即承受通常的轮询〔polling〕机制,则太铺张CPU资源了。所以需要操作系统和CPU能够一起供给某种机制,让外设在需要操作系统处理外设相关大事的时候,能够“主动通知”操作系统,即打断操作系统和应用的正常执行,让操作系统完成外设的相关处理,然后在恢复操作系统和应用的正常执行。在操作系统中,这种机制称为中断机制。中断机制给操作系统供给了处理意外状况的力气,同时它也是实现进程/线程抢占式调度的一个重要基石。在操作系统中,把三种特别的中断大事。由CPU外部设备引起的外部大事如I/O中断、时钟中断、把握台中断等是异步产生的,与CPU的执行无关,我们称之为异步中断〔asynchronousinterrupt〕也称外部中断,简称中断(interrupt)。而把在CPU执行指令期间检测到不正常的或非法的条件〔如除零错、地址访问越界〕所引起的内部大事称作同步中断〔synchronousinterrupt,也称内部中断,简称特别〔exception。把在程序中使用恳求系统效劳的系统调用而引发的大事,称作陷入中断(trapinterrupt,也称软中断〔softinterrupt〔systemcall〕trap。在后面的表达中,假设没有特别指出,我们将用简称中断、特别、陷入来表示这三种特别的中断大事。2.源码分析trap.cxv6对不同的中断的处理过程以及中断表的初始化。中断初始化tvinit2.源码分析trap.cxv6对不同的中断的处理过程以及中断表的初始化。中断初始化tvinit过程中主要是对idt表进展初始化。其中vectors中存放的是每个中断处理程序的入口地址。vectorsvectors.Sperlvectors.pl2223可以看到,Systemcall中断权限为用户权限,也就是说只能int0x30tickslock这个锁进展初始化,这个锁是用来处理时钟中断的。idtinitidt表的。idtinittvinitidtinitCPU调用。而tvinit过程只需要被调用一次。vectors.S&vectors.plvectors.Svectors.pl生成的。其中定义了每个中断的入口程序和入口地址〔存储在vecotrs数组中。可以留意到,中断分成两类:一类是压入错误编码的(errorcode)另一类不会压入错误编码。因此对于其次类,vectors.S将压入一个0。此外vectors.S还会将中断号压入栈。在压完两个必要的值之后,全部中断都将统一的跳转进入alltraps入口程序。中断处理过程trap函数的实现trap过程便是对中断进展处理的。全部的中断在经过中断入口程序(trapasm.S中定义〕后,都会最终跳转到这里。其处理过程如下:在37~45行,假设中断是系统调用,则通过syscall过程完成系统调用的处理。值得留意的是,这里进展了当前进程是否被其他进程kill的状况。也就是说,假设一个进程被Kill,那么此进程将在进入或退出内核态时被切断。48~56行是对不同的中断进展处理。caseIRQ_OFFSET+IRQ_TIMER是处理时钟中CPU0CPUtickssleeping状态的进程进展检查〔通过wakeup)。在wakeup则RUNNABLE;57~60ide_intr完成磁盘中断处理;61~64kbd_intr完成键盘中断处理;6~69行打印出产生的IRQ_SPURIOUS[]72~82行,推断假设是在内核执行时产生的中断,则系统挂起;假设是在用户态执行p->killed=1,表示要杀死此进程84~88行,将检查当前进程的p->killed,假设是非零且在用户态引起的中断,则调用exit函数退出此进程;9~93行,推断假设当前进程占用了CPU〔即cp->state==RUNNING,且是时钟中断,则调用yield函数,让当前进程放弃所在CPU,选择其他进程占用当前CPU。trapasm.Strapasm.S在这个文件中,主要是将存放器进展保存。9~11行都是将相关存放器压入到栈。存放器值在栈中的布局可以参考x86.h中trapframe的定义。需要留意到的是栈底是在内存的高地址位置,trapframe构造是从低到高放置的。14~16trap.c中traptraptrapframeesp存放器压入栈,其正好是trapframe的地址。在从trap返回之后,将开头保存的全部存放器恢复〔26~28行,然后将中断编号和错误号弹出栈即可。然后调用iret进展返回。syscall.c这个文件的主要目的是处理系统调用,依据系统调用的编号安排到不同的处理函数中去。其中文件中还供给了提取参数的过程。fetchintfetchstr是从进程〔p)addrkernelip。由于addr是进程中的地址,其对应的物理地址在内核态的虚拟地址是不同的,因此需要转换。转换是十paddrp->mem+addrpp->memp->sz大小的连续空间。需要留意的是,fetchintfetchstr都需要推断参数给出的内存地址是否超过了进程所安排的内存范围。argint,argptrargstrsystemcall中传入的参数。进程在进程调用前,都会把参数压入fetchintfetchstr猎取参argintnncp->tf->esp+4+4*n。syscall过程是将系统调用安排到不同的处理函数。处理后的返回结果存到cp->tf->eax中。这eax〔trapasm.S)。sysproc.cproc.c中的函数sys_sleep。一进入这个函数时,ticksticks0中。接着始终ticks-ticks0即实际睡眠时间超过预定的时间后就返回。由于不能始终占用CPU,sleepSleeping状态,参与休眠队列。(filesystem)概述本章将给出xv6文件系统实现的概貌。读者将学习以下一些内容:什么是文件系统?什么是文件?什么是名目?I/OBuffer有何作用?xv6的文件系统有哪些重要局部组成?xv6如何实现创立一个文件?xv6如何实现读写文件?很多应用需要对数据进展长期保存和访问,这样就需要文件系统的支持。操作系统中负责治理和存储文件信息的软件机构称为文件治理系统,简称文件系统。文件系统由三局部组成:与文件治理有关的软件、被治理的文件以及实施文件治理所需的数据构造。从系统角度来看,文件系统是对文件存储器空间进展组织和安排,负责文件的存储并对存入的文件进展保护和检索的系统。具体地说,它负责为用户建立文件,存入、读出、修改、转储文件,把握文件的存取,当用户不再使用时删除文件等。xv6的文件系统是整个操作系统中代码量最大的一局部了,但照旧只是一个格外简洁的实现。UnixUNIX文件系统种类具有类似的通用构造,其中心概念是超级块〔superblock〕,i节点〔inode〕,数据块〔datablock〕名目块〔directoryblock〕,和间接块〔indirectionblock。超级块包括文件系统的总体信息,比方大小(其准确信息依靠文件系统)。i节点包括除了名字外的一个文件的全部信息,名字与i节点数目一起存在名目中,名目条目包括文件名和文件的i节点数目。i节点包括几个数据块的数目,用于存储文件的数据。i节点中只有少量数据块数的空间,假设需要更多,会动态安排指向数据块的指针空间。这些动态安排的块是间接块;为了找到数据块,这名字指出它必需先找到间接块的号码。xv6API、文件系统、BufI/O通讯。FDFileRead和Write等函数与硬件设备进展交互,从而隐蔽了很多实现的细节,简化了很多上层程序的操作。Buf缓存构造是用来缓存需要写入硬件设备的数据和从硬件设备上读出的数据。Buf可以对硬件设备的操作进展统一的调度,从而提高效率。最底层的便是直接对硬件设备进展调度。7.1xv6文件系统构造FD文件描述符,File文件构造和源码分析sysfile.c此文件定义了很多有关文件系统的系统调用。xv6中的系统调用是针对文件描述符进展的。每File。有可能多个文件描述指向同一个文件。每个文件描ofile记录了其指向的文件构造。下面对每个过程进展介绍。argfdnn个参数读取出来(20行)ofile找到相应的文件构造〔22行。ofile数组中查找一个没有使用的文件描述符,然后返回即可。sys_readosfile读取出文件描述符所指向文件构造fileread进展文件读取。sys_writesys_read类似,只需要找到相应的文件构造,调用filewrite对文件构造进展写操作。同样,sys_dup、sys_closesys_fstat都是API进展操作,这里就不再赘述了。sys_linkxv6中,一个名目中存储的是一个个文inodeinodeinode。sys_link就是用来建立这种指向的。为了避开形成大于1的环,dir的link只能指向一个文件,而不能是名目(122~124行116~128inode1。然后在130~136sys_unlink是用来取消一个硬链接。就是在名目中找到相应的表项,进展删除。create过程是用于建立相应的file.h每个文件构造都对应着一个磁盘设备上的真实文件、或一个硬件设备、或者通讯管道。从File的构造定义可以看出,File构造主要分成两种类型,一种是INODE(可能是磁盘上的文件,也可能是硬件设备,另一种是Pip〔管道。假设是INODE型,则ip指针则指向其对应的pipePIPEreadablewritable是用来加ref则是表示被整个系统的用户进程应用了多少次(TODO:不同进程INODE层?)。file.c此文件中供给了对FILE构造的一些根本操作,例如FILE文件构造的安排〔filealloc的复制〔filedup、文件构造的关闭(fileclose)、文件读取(fileread)和文件写入(filewrite)。全部FILE文件构造在系统中都有一个统一的列表保存,这个列表的大小限制了整个系统可以SMP构造,在访问这个列表时需要加上锁来保证互斥的资源访问。filealloc是用来安排一个FILE构造的,也就是从文件列表中选取一个状态为FD_CLOSED的FD_NONE1。fork中。fileclose是将一个文件的引用计数减一。比方某个用户进程将此文件构造关闭了。当引用计数变为0时,说明系统中没有任何一处翻开此文件,此时可以收回此文件构造。在回收时,同时要调用文件构造下层构造(PIPEINODE)的关闭。filestat是返回一个文件构造的统计信息。只有当此文件构造类型是INODEC时才有效。返回的统计信息有文件大小,文件链接数等等。分别是通文件构造读取和写入数据。两个函数都是调用下层构造相应的函数file_table_lock锁。但全部的下层构造都有其自身的加锁机制。磁盘文件系统和源码分析文件系统主要是以INODE构造进展操作的。INODE可以是一个文件,也可以是一个文件夹。用户进程通过文件路径来进展对INODE的查询和访问。INODE在xv6文件系统中有两种类型,一种是在系统实际运行时在内存中的INODE〔即fsvar.h中的inode构造,另一种是在磁盘上INODE〔fs.hdinode)INODE是用于操作系统对文件访问进展控INODEdinode则是用于组织这个文件系统在磁盘上的存储构造。fsvar.h&fs.hxv6文件系统在磁盘上的组织构造。xv6对磁盘空间的划分是以块〔block)为单dinodeblock组成。在磁盘上,xv6文件系统从低地址到高地址(即从0块到最终一块〕的布局为:超级块(superblock)、dinode构造列表(inodes)用状况的统计表(blockin-use-bitmap)和数据块。其中超级块的作用是给出磁盘文件系统的根本信息,包括文件系统总的块数,数据块的数目以及dinode的数目。超级块只占一个块〔blockdinodedinodedinode都有自己的编号。dinode构造中记录的文件类型(文件或名目、设备、硬链接数、文件大小和此文件所占用的数据块。占用数据块的编号存在addrs中,其中addrs[0]~addrs[NDIRECT-1]直接指向一个数据块;而addrs[INDIRECT]指向一个块,块里存放的都是其他被此文件占用的数据块的地址,因此是addrs[INDIRECT]是间接指针。磁盘块使用状况统计表是一段连续的磁盘空间,其中每一比特对应了整个盘上某块的使用状况。假设第ibit为1,则表示磁盘上的第0块被占用。磁盘中剩下的块都为数据块。留意:以上每一局部都占用整数个块,有些构造可能没有把其最终一0。fs.creadsbsuperblock。bzero,balloc,bfree都是数据块相关的操作。在操作中都是对有bufblockballoc,bfree在操作之后都需要修改磁盘块使用状况统计相应的比特位。inode操作相关的函数。在文件系统中,icache构造缓存当前系统中全部inodeinodeFile文件构造或者是进程所处的当前名目cwdinode0时,inodeinode都有一个inumdinode的列表的编号。igeticacheinuminodeicacheinode,则inoderef1。idupinodeforkFile文件构造被复制是会发生这个状况。ilockinodeinodeI_BUSY,同inodeinode使用权时,假设觉察已被其他进程SLEEP状态。知道其他进程放弃使用权后,用wakeup将其唤醒。需要留意的是在抢inode使用权时,照旧可能消灭RACE状态(TODO)。抢到使用权后,假设觉察ip->flagsI_VALID,则从磁盘上读入。iunlockinode的使用权,同时唤醒等待这把锁的进程。iput1inode。iallocinode进展安排。这个算法对磁盘进展挨次查找空闲的inode,速度实际上比较慢。iupdate是将内存中的内容更到磁盘。bmapinoden个块(block)n块是直接块,则可以马上返回。否则要加载block然后读到相应的块,然后返回。itrunc、stati、readiwriteiinode的数据访问。dirlookup、dirlink、skipelem、_namei都是对文件路径进展处理,相比照较简洁,这里便不再赘述。需要留意的是,dirinodedirent项,描述了文件夹inode编号。I/O缓存Buf构造和源码分析xv6bufblock块进展缓存。bufLRUbuf总是放在链表的首部。bio.cbinitbuf链表初始化,并将其链成一个表。bgetbuf。首先在bufbufbuf存储扇区。bread是bgetbufB_VALID,则通过ide_rw进展磁盘同步。bwritebufbwrite之前需要在外部对buf,从而保证全都性。brelsebufbuf访问完毕时调用的。此时基于LRUbufbuf链表的头部。ide.cide磁盘进展读写操作。I/O读写是异步的。ide_rwide_queue进展排队。在ide_rwide_queuedisk没有开头读写,则唤起disk读写。(141~142行145~146进展轮询等待读写进程的完成。轮询中并不是盲sleep当前进程,等待进程完成是被唤起。ide_start_requestbufb进程恳求发送到磁盘。当进程完成时,磁盘将发出完成的硬件中断。ide_intr则是相应此中断的过程。ide_intr106~108行去除状态,并唤醒等待此bufide_queue有后继进程,则启动此进程。第八章对称多处理〔SMP/MultiCore〕支持概述本章将给出xv6多处理器支持的实现概貌。读者将学习以下一些内容:SMP系统?什么是PIC,LAPIC,IOAPIC?xv6CPU的?xv6CPU之间的中断信息传递的?xv6如何初始化主处理器〔BP〕和从处理器
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 财务部年终报告开创新局面引领新风尚
- 手工艺行业卫生卫生控制
- 2025-2030全球电子后视镜系统行业调研及趋势分析报告
- 2025-2030全球联合收割机皮带行业调研及趋势分析报告
- 2025-2030全球3D 打印陶瓷丝行业调研及趋势分析报告
- 2025年全球及中国智能睡眠盒行业头部企业市场占有率及排名调研报告
- 2025-2030全球IP65工业显示器行业调研及趋势分析报告
- 2025-2030全球机器人用立体摄像头行业调研及趋势分析报告
- 2025-2030全球不锈钢面板安装显示器行业调研及趋势分析报告
- 2025-2030全球全液压解耦系统行业调研及趋势分析报告
- 中国储备粮管理集团有限公司兰州分公司招聘笔试真题2024
- 第1课 隋朝统一与灭亡 课件(26张)2024-2025学年部编版七年级历史下册
- 提高金刚砂地坪施工一次合格率
- 【历史】唐朝建立与“贞观之治”课件-2024-2025学年统编版七年级历史下册
- 产业园区招商合作协议书
- 2024年广东省公务员录用考试《行测》真题及答案解析
- 2025新译林版英语七年级下单词默写表
- 盾构标准化施工手册
- 天然气脱硫完整版本
- 中欧班列课件
- 光伏十林业可行性报告
评论
0/150
提交评论