南大面试课程ch2 3 minix进程_第1页
南大面试课程ch2 3 minix进程_第2页
南大面试课程ch2 3 minix进程_第3页
南大面试课程ch2 3 minix进程_第4页
南大面试课程ch2 3 minix进程_第5页
已阅读5页,还剩79页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

2.10 Minix

3

进程概述2.10.1

MINIX的结构第2页

页Minix的层次结构内核时钟任务系统任务磁盘驱动终端驱动进程管理文件系统信息服务器网络服务器Init进程用户进程用户进程用户进程……用户进程网卡驱动第3页

页MINIX

3被组织成四层,每一层执行一组定义明确的功能。第1层第4页

页内核处理所有进程间的消息最底层进行进程调度支持对I/O端口和中断的访问时钟任务时钟中断驱动处理时钟定时器时钟任务也是一个进程,在进程队列中排队系统任务为上层驱动程序和服务器提供一组特权内核调用读写I/O端口、跨地址空间复制数据等系统任务是单独的进程,并有自己的调用堆栈第2层第5页

页第2、3、4层与第1层有本质的区别,不能执行特权指令。都是以用户模式运行。第2、3、4层的进程调用系统调用的能力不同。第2层的称为设备驱动程序(devicedrivers),具有最多的权限。可以请求系统任务代表它们从I/O端口读数据或向I/O端口写数据。请求刚刚读取的数据副本拷贝到另一个进程的地址空间。第3层第6页

页第3层包含了服务器,即向用户进程提供有用服务的进程。进程管理器(ProcessManager,PM)执行所有涉及启动或终止进程的MINIX3系统调用。例如fork,exec

和wait等。负责执行与信号有关的系统调用,例如alarm和kill等。PM还负责管理内存,例如发出brk系统调用。文件系统(File

System,FS)负责执行文件系统的调用,如read,mount和chdir等。第3层—内核调用和系统调用的区别第7页

页内核调用(kernelcall)和POSIX系统调用(systemcall)

有本质的区别。在MINIX3中用户进程发出的系统调用将被转换为发往服务器进程的消息。服务器进程被禁止执行实际的I/O操作,也不能改动系统表及完成其他操作系统一般都有的功能。内核为驱动程序和服务器提供一组服务—内核调用。这些对普通用户进程不可用的服务,允许驱动程序和服务器执行实际I/O操作、存取内核表以及其他它们所需要的功能,而不需要在内核内部。

注意:用户进程不能产生内核调用。服务器进程相互之间、服务器进程与设备驱动程序之间以及服务器进程与内核之间通过消息进行通信。第3层—IS

&

RS第8页

页信息服务器(informationserver,IS)负责提供其他驱动程序和服务器的调试和状态信息的工作。再生服务器(reincarnationserver,RS)启动或重启那些不与内核一起加载到内存的设备驱动程序。如果驱动程序在操作过程中失败,那么再生服务器检测到这个失败,并杀死这个驱动程序(如果它没有死的话),重启一个驱动程序的新的副本,从而使整个系统具有更好的容错能力。这一功能在大多数操作系统中是没有的。第3层—增加新的服务器第9页

页在进程管理器和文件系统之外,可以补充网络服务器等其他服务器补充。进程管理器和文件系统也可以被其他服务器取代。通过当MINIX3启动时或启动后向系统添加另外的服务器来实现。设备驱动程序通常在系统启动时开始运行,但也可以在系统运行时启动。设备驱动程序和服务器都被编译并以一般可执行文件的形式存储在磁盘上。与用户进程不同,当系统处于活动状态时驱动程序和服务器进程不会终止。系统进程是操作系统的一部分。它们不属于某一个特定的用户,大部分会在系统第1个用户登录前启动。第4层第10页

页第4层包括了所有的用户进程,如init、shell程序、编辑器、编译器和用户自己编译好的可执行程序。系统对象每个进程是一个对象。内存数据的值OS为其保留的值指令指针的值堆栈栈顶的值寄存器的值第11页

页OS要做的事情I/O

服务进程间通信进程切换保留状态恢复状态进程创建、清除对象

U.code U.data U.register U.kernel U.kernel.fdU.kernel.fd[i].pos2.10.2

MINIX进程管理第12页

页引导(

Bootstrap

)第13页

页Bootstrap(靴带)是皮鞋后部的一条小带子或一个小环,它可以使你方便地把鞋子穿起来。软盘启动硬件(BIOS)从引导盘上将第1道第1个扇区(bootstrap)读人内存并从那里开始执行。引导程序很小,因为它必须能容纳在一个扇区(512字节)里。引导程序装入一个更大的程序boot,由boot装入操作系统。硬盘启动硬盘被分成若干个分区(partition),整个硬盘的第1个扇区包括一段小程序和磁盘分区表(partition

table)。两者合在一起称为主引导记录(Master

Boot

Record,MBR)。程序部分被执行以读人分区表并选择活动分区(active

partition)。活动分区的第1个扇区有一个引导程序,它随后被装入并执行以查找并启动程序boot。启动(boot)第14页

页MINIX3的boot程序将在软盘或硬盘分区上找一个包含多个部分的文件(引导映像,bootimage),并将各部分装到内存的适当位置。Minix3的引导映像内核,时钟任务和系统任务;磁盘驱动程序;再生服务器;它可以把一个初始化后加载的普通进程赋予特定的优先级和权限,使得它们成为系统进程。也可以根据驱动程序的名字重新启动崩溃的驱动程序。RAMdisk、控制台、日志驱动程序和init程序。boot需要完成属于磁盘任务和文件系统范围的操作。boot要准备好内核初始化程序的运行环境,切换到内核。初始化第15页

页内核先启动系统任务和时钟任务启动进程管理器和文件系统。然后进程管理器和文件系统合作加载作为引导映像一部分的其他服务器和驱动程序。当所有这些都开始运行并完成初始化之后,它们将阻塞,等待执行某种操作。只有包含在引导映像中的所有任务、驱动程序和服务器都阻塞之后,第1个用户进程init才开始运行。再生服务器第16页

页进程管理器是用户空间内运行的第1个进程。它被赋予PID为0。它既不是其他任何进程的子进程,也不是其他任何进程的父进程。再生服务器被作为其他所有在引导映像中启动的进程的父进程(例如驱动程序和服务器)。当这些程序需要重启时,应该通知的是再生服务器进程。init进程被作为再生服务器进程的一个子进程。init被赋予的进程标识符为1(尽管init不是运行的第1个进程)init进程第17页

页init进程首先执行/etc/rc脚本这一脚本启动其他不在引导映像中的驱动程序和服务器。所有通过rc脚本启动的进程都是init进程的一个子进程。rc脚本的一个重要功能是检查可能由上次系统崩溃所引起的文件系统错误:shutdown

-C命令查wtmp文件中最后一条记录是否是关闭信息。如果不是,将假定上次是非正常关机,执行fsck检查所有的文件系统。最后,init进程为每一个终端创建一个子进程。init读取/etc/ttytab文件,该文件列出了所有可能的终端设备。通常每个子进程都执行文件/usr/bin/getty,打印出一条信息,然后等待输入一个用户名。当用户输入用户名登录时,/usr/bin/login被调用,并使用这个用户名作为参数。在成功登录之后,/bin/login执行用户的shellshell等待用户键人命令,并为每条命令创建一个新的进程。Minix3的重要系统组件组件描述通过什么加载kernel内核+时钟和系统任务(在引导镜像中)pm进程管理器(在引导镜像中)fs文件系统(在引导镜像中)rs重启服务器和驱动程序(在引导镜像中)memoryRAM盘驱动程序(在引导镜像中)log缓存日志输出(在引导镜像中)tty终端和键盘驱动程序(在引导镜像中)driver磁盘(bios或软盘)驱动程序(在引导镜像中)init所有用户进程的父进程(在引导镜像中)floppy软盘驱动程序(如果从硬盘启动)/etc/rcis信息服务器(用于调试转储)/etc/rccmos读CMOS时钟来设置时间/etc/rcrandom随机数产生器/etc/rcprinter打印机驱动程序/etc/rc第18页

页用户进程第19页

页一个进程的所有信息被保存在进程表中进程表划分成内核、进程管理器和文件系统三部分,分别拥有它们各自所需要的那些域。当出现一个新进程(通过fork)或者一个老进程终止(通过exit或信号)时,进程管理器首先更新它那部分进程表,然后向文件系统和内核发送消息,以通知它们进行相应的操作。2.10.3

MINIXDE

消息第20页

页消息第21页

页MINIX

3提供了三条原语来发送和接收消息send(dest,

&message);当一个进程发送消息到目标进程而目标进程并不在等待消息时,发送进程将阻塞,直到目标进程调用receive为止。MINIX3使用这种方法避免了缓冲那些发送出去但未被目标进程接收的消息所带来的问题。它很简单,避免了缓存管理。所有的消息长度固定,并且在编译时确定下来,缓存溢出问题这个常见的错误就从结构上消除了。第4层的用户进程可以向第3层的服务器发送消息,第3层的服务器可以向第2层的驱动程序发送消息。限制进程间消息传递的根本原因是如果允许进程A通过send向进程B发送消息,那么可以允许进程B通过receive从进程A接收消息,但是不能允许B向A发送消息。如果进程A尝试向进程B发送消息而阻塞,同时进程B尝试向进程A发送消息而阻塞,这将导致死锁。用户层发送消息第22页

页send(dest,

&message);

send:

lib/I386/rts/ipc.s→proc.c/syscall→proc.c/mini_sendpush

ebpmov ebp,

esppush

ebxmovmovmovinteax,

SRC_DST(ebp)ebx,

MESSAGE(ebp)ecx,

SENDSYSVEC!

eax

=

dest-src!

ebx

=

message

pointer!

_send(dest,

ptr)!

trap

to

the

kernelebxebppoppopret消息第23页

页receive(source,

&message);sendrec(src_dst,

&message);发送消息,等待接收者进程的响应,收到响应后再回复。notify(dest);通知,不阻塞,继续执行。2.10.4

MINIX3的进程调度第24页

页Minix3中的进程调度第25页

页进程被阻塞的情况进程请求从设备输入时时钟中断设备中断异常软件中断每当一个进程阻塞时,都有机会重新确定哪个进程最需要运行机会。在一个进程终止时也要执行该操作。多级排队系统第26页

页MINIX3调度器使用一个多级排队系统。一共定义了16个队列,最低优先级队列只由IDLE进程使用,IDLE进程在系统没有其他任务时运行。用户进程启动时默认的优先级比最低优先级要高一些。服务器进程处于比用户进程具有更高优先级的队列当中。驱动程序进程处于比服务器进程更高优先级的队列当中。系统和时钟任务处于最高优先级队列当中。时间片时间片:进程在被抢占前所允许运行的最大时间间隔。用户进程有一个较小的时间片。驱动程序进程和服务器进程通常可以运行到阻塞,为了防止故障,它们是可抢占的,但具有一个大的时间片。Minix启动后初始的进程队列情况第27页

页多级排队系统第28页

页运行超时的进程仍处于就绪态,但被放到它所在队列的尾端。如果一个用完了时间片的进程,仍然是上一次运行的进程,将把该进程放到一个较低优先级队列的队尾以降低它的优先级。可以认为它卡在了一个循环中,从而出现了阻止其他低优先级进程运行的征兆。如果这个进程又运行超时,而还有其他进程得不到运行,它的优先级将再一次降低。最终使其他的进程都得到机会运行。一个被降低优先级的进程仍有机会提高它的优先级。如果一个进程用完了它的时间片,但没有妨碍其他进程运行,

它的优先级将得到提高,直到该进程所允许的最大优先级为止。如果进程转为非就绪的时候没有用完它的时间片这说明它在I/O上阻塞,当该进程再次转为就绪时就被放到队首,并分配上次所剩余的时间片。给用户进程更快的I/O响应。系统进程不会被用户进程阻止运行。2.11 Minix3中进程的实现第29页

页2.11.1

MINIX源代码的组织第30页

页Minix第31页

页Minix网站()上有最新的版本,它具有新的特性及其配套软件和文档。C语言源代码的完整路径是/usr/src用一个顶层目录为src/的路径字符串来引用MINIX3的源程序文件。源代码目录树下的每一个目录都包含一个名为Makefile的文件,它用来完成UNIX标准下的make命令。Makefile文件控制它所在目录中的文件的编译,有时也会包括它的一些子目录中的文件。src/目录树的全部或者部分也可以被重新分配位置每个源目录内的Makefile都是使用C源程序所在目录的相对路径。Minix的源码组成includesysibmminixnetKernel

微内核systemServers—

服务程序PMFSRSInetISInit…………第32页

页drivers—驱动程序At_winiBios_winiCmosFlopyTty…………boot

—引导和启动Lib—用户库函数PosixI386RTSSyscallSyslib…………头文件目录第33页

页include/目录包含了许多符合POSIX标准的头文件,它又包含三个子目录sys/:包含POSIX头文件。minix/:包含操作系统使用的头文件。ibm/:包含IBMPC特有定义的头文件。源文件目录第34页

页kernel/

第1层(调度、消息、时钟和系统任务)drivers/

第2层(磁盘、控制台、打印机等的驱动程序)。servers/

第3层(进程管理器、文件系统、其他服务器)。src/servers/inet/:网络服务器的源代码src/lib/

库例程(如open,read)的源代码。src/tools/

用于构建MINIX3系统的Makefile和脚本。src/boot/

引导和安装MINIX3的代码。mands/,其中包含工具程序(如cat,甲,date,ls,

pwd以及200多个其他程序)的源代码。编译在src/tools/目录下运行make命令来编译MINIX3。src/include/目录下的头文件将在/usr/include/目录下产生一个新的副本。src/kernel/目录中的源文件以及

src/servers/和src/drivers/中的一些子目录将被编译成object文件。src/kernel/中所有的object文件再链接成一个可执行程序kernel。src/servers/pm/目录中的所有object文件也将链接成一个可执行程序pm。src/servers/fs/目录中的object文件则链接为fs。作为引导映像的组成部分的其他程序也在它们各自的目录中被编译和链接。链接后的程序被分离和加载后的内存分配情况如右图所示。第35页

页安装第36页

页installboot将kernel,pm,fs,init以及其他引导映像中的组件,添加一些数据以使其长度扇区大小的整数倍(以便可以更容易地独立加载该部分)。并将其连接为一个文件。这个新的文就是启动映像文件,可以将其复制到软盘或者硬盘分区的/boot或者/boot/image/目录中。2.10.2

引导MINIX

3第37页

页引导记录第38页

页主引导保留区分区1引导分区2引导主引导程序分析分区表,找到活动分区位置。从活动分区读取第一个扇区,作为引导程序。引导程序加载启动程序boot。一个分区可以有多个子分区。主引导保留区分区1主引导分区2引导子分区1引导子分区2引导boot的定位第39页

页将MINIX3引导扇区写入硬盘时要对它进行修改写入操作由一个特殊的程序installboot完成,该程序添加个扇区号以便在其分区或子分区中找到boot程序。因为在装入操作系统之前无法通过目录和文件名来定位一个文件。boot不仅可以装入操作系统,而且作为一个监控程序,它许用户改变、设置和保存不同的参数。boot从它所在分区的第2个扇区中寻找一套可用的参数。MINIX3保留每个硬盘分区的前1KB作为一个引导块。但其中只有一个512字节的扇区被ROM引导程序或主引导扇区装入,这样,另外512字节可以用来保存设置信息。这些信息控制引导操作,并且被传到操作系统本身。默认的设置显示一个只有一个选择项的菜单,引导MINIX3。但该设置信息可以被改变,以显示一个更复杂的菜单。这样,便允许引导其他操作系统(通过装入并执行其他分区的引导扇区)或使用不同的选择项来引导

MINIX3。默认设置也可以被修改,以旁路掉该菜单而直接引导MINIX3。boot

加载系统镜像和传递参数第40页

页boot并不是操作系统的一部分可以使用文件系统的数据结构来找到操作系统镜像。boot寻找一个默认文件在/boot/image下,若存在文件则加载之。它同Minix

3一起运行,但Minix

3正常关闭后,该引导监控程序会重获得控制权。引导映像中的每一个文件都包含一个头文件由它标识在加载完可执行代码初始化的数据后应为那些未初始化的数据及栈预留多大的空间,以使下一个程序能在合适的地址行加载。MINIX3镜像组件的头文件a.out被抽取为引导内存空间的一个数组,其基地址被传送给内核。其他一些信息,如引导参数,必须由引导监控程序传送给操作系统。2.10.4

系统初始化第41页

页初始化的主要工作第42页

页Minix3的初始化可以分为两个阶段:低层初始化和高层初始化。低层初始化由mpx386.s完成,主要有以下工作:GDT,IDT的初始化通用段寄存器的初始化:cs,ds,es,fs,gs全局数据结构的初始化:kinfo

,machine高层初始化由main()完成,主要有以下工作:8259中断控制器的初始化进程表和进程特权级表的初始化为启动镜像中的进程分配空间调度进程运行起始位置初始化代码的32位版本位于文件mpx386.s中。MINIX

3的启动牵涉到几次控制权转移

它们发生在mpx386.s中的汇编语言例程和start.c及main.c中的C语言例程之间。在mpx386.s中,从Minix:标号开始,此时BootMonitor已经将控制权转移到此。…高地址a.out数组的基地址boot

parameters

length由boot

monitor压入boot

parameters

offsetboot

monitor返址←——sp低地址第43页

页BootMonitor中设置的GDT第44页

页BootMonitor中会将系统从实模式切换到保护模式。在BootMonitor中设置的GDT表项内容如下:0GDT_INDEX:1IDT_INDEX:2DS_INDEX:3ES_INDEX:4SS_INDEX:5CS_INDEX:6MON_CS_INDEX:7不用GDT描述符IDT描述符Kernel

DS

描述符Kernel

ES描述符Boot

monitor

SS描述符Kernel

CS描述符Boot

Monitor

CS描述符这时,CS:EIP指向标号为Minix:处DS也已经指向了核心数据段SS:SP依然指向Boot的栈顶。压入ebp,esi,edi

首先将sp扩展为32位的,因为BootMonitor中这是16位的。第45页

页!

monitor

stack

is

a

16

bit

stackmovzxpushmovpushpushesp,

spebp

ebp,

espesiedi将BootMonitor中的GDT拷贝到内核的地址空间中,然后在以后对其进行更新。初始化对象kinfo和machine将boot提供的相关参数压栈,为调用函数kernel/start.c/cstart做准备。cstart()函数的主要作用是对两个全局结构体kinfo和machine结构体的初始化。kinfo是记录内核的信息的,任何需要知道内核信息的地方都需要查看此结构体的参数machine结构体主要是记录处理器的一些硬件信息,比如总线类型,是286系列还是386系列,内核中涉及到硬件体系结构的地方都需要此结构体提供信息。字段值Code_baseseg2phys(cs)Code_size(phys_bytes)

&etextData_baseseg2phys(ds)Data_size(phys_bytes)

&endParams_baseseg2phys(mds)+

parmoffParams_sizeMIN(parmsize,sizeof(params)-2)Nr_procs100Nr_tasks4Release[6]“3”Version[6]“1.1”字段值Pc_at具体的值从boot参数中提取Ps_mca具体的值从boot参数中提取Processor具体的值从boot参数中提取Protected具体的值从boot参数中提取Vdu_ega具体的值从boot参数中提取Vdu_vga具体的值从boot参数中提取第46页

页系统GDT的更新cstart()的另外一个重要工作就是调用

kernel/protect.c/prot_init()进行GDT,IDT和TSS的初始化。因为先前使用的GDT是从BootMonitor拷贝过来的,这里需要根据

kinfo结构体提供的内核代码段地址,代码段大小,数据段地址,数据段大小等重新设置GDT表中S_INDEX,DS_INDEX等的内容。这主要通过init_codeseg()和init_dataseg()两个函数完成的。中断描述符表是通过int_gate()这个函数完成的。这个函数通过将中断向量,中断处理函数,特权级等信息组装成一个中断描述符放入IDT表中。在从cstart返回之后,Igdt和lidt指令通过向其对应的寻址寄存器装入相应的值。jmpf

CS_SELECTOR:csinit这条指令(CS寄存器有影子数据,当远跳转时要根据描述符表更新)

第47页

页Minix3的GDT内容序号名称基址限长(字节)DPL0未用001GDT描述符gdt[]的物理地址gdt[]的长度减12IDT描述符idt[]的物理地址idt[]的长度减13核心DS描述符核心数据段物理始址核心数据段长度减104核心ES描述符0232-115monitor

DS描述符Boot数据段的物理始址boot数据段长度减16核心CS描述符核心代码段物理始址核心代码段长度减107monitor

CS描述符Boot代码段的物理始址Boot代码段长度减18TSS描述符tss的物理地址tss结构的长度减109286

DS描述/p>

ES描述符0232-111112131415LDT0的描述符proc[0].p_ldt的物理地址proc[0].p_ldt[]的长度减1016LDT1的描述符proc[1].p_ldt的物理地址proc[0].p_ldt[]的长度减10…LDT[NR_TASKS+NR_PROCS]的描述符LDT[NR_TASKS+NR_PROCS].p_ldt的物理地址proc[0].p_ldt[]的长度减10第48页

页高层初始化第49页

页低层初始化的工作到此完成,下面跳转到main函数继续高层初始化。首先使用intr_init()对8259中断控制器进行初始化。初始化进程表Struct

proc

proc[NR_TASKS

+

NR_PROCS];系统中有一个image[]数组。数组类型为boot_image结构体。image[]数组记录了系统启动时需要加载的所有进程的信息,比如进程号,时间片,队列,名称等等。进程表初始化后,这些进程以便将来可以被调用。最后跳转到restart()函数,调用第一个进程来运行。至此,初始化完毕。2.5

中断内核第51页

页时钟中断函数的注册typedef struct

irq_hook

{……}

irq_hook_t第52页

页struct

irq_hook

*next;next

hook

in

chainint

(*handler)(struct

irq_hook

*);interrupt

handlerint

irq;IRQ

vectornumberint

id;id

of

this

hookint

proc_nr;NONE

if

not

in

useirq_id_t

notify_id;id

to

return

on

interruptirq_policy_t

policy;bit

maskfor

policy内核(glo.h)有一个中断链表的指针数组irq_hook_t

*irq_handlers[NR_IRQ_VECTORS];当中断发生的时候,根据中断号,取得其中的一个指针。再在这个链表上遍历需要处理这个中断的处理函数。时钟中断函数的注册第53页

页时钟任务需要处理时钟中断。时钟任务在初始化的时候注册时钟中断。Kernel/clock.c/init_clock()

ch2-src\clock.cPRIVATE

voidinit_clock(){clock_c_nr

=

CLOCK;………………put_irq_handler(&clock_hook,

CLOCK_IRQ,

clock_handlerenable_irq(&clock_hook);

/*

kernel/klib386.s

*/}时钟中断函数的注册第54页

页kernel/i8259.c/put_irq_handler

(&clock_hook,CLOCK_IRQ,clock_handler)将中断处理的数据结构挂在链表上。…………hook->next

=

NULL;hook->handler

=

handler;hook->irq

=

irq;hook->id

=

id;…………}void

put_irq_handler(hook,

irq,handler){…………line

=

&irq_handlers[irq];id

=

1;while

(*line

!=

NULL)

{if

(hook

==

*line)

return;line

=

&(*line)->next;id

<<=

1;其它中断的处理函数的注册第55页

页时钟中断的处理函数注册kernel/clock.c/init_clock()

调用kernel/i8259.c/put_irq_handler()它们在一个进程空间中,可以直接调用put_irq_handler。其它在驱动程序初始化的时候要统通过系统调用调用lib/syslib/sys_irqctrl.c/sys_irqctl(……)

源码调用lib/other/taskcall.c/_taskcall(SYSTASK,SYS_IRQCTL,&m_irq);向系统任务发消息。源码kernel/system.c/sys_task()源码(*call_vec[call_nr])(message);kernel/system/do_irqctrl.c/do_irqctrl(message);

源码在.h中定义了系统调用对应的消息类型。# define

SYS_IRQCTL (KERNEL_CALL

+

19) /*

sys_irqctl()

*/lib/syslib/sys_irqctrl.c/sys_irqctl(……)PUBLIC

int

sys_irqctl(req,

irq_vec,

policy,

hook_id)int

req; int

irq_vec; int

*hook_id; hook

at

kernel

*/{ message

m_irq; int

s;m_irq.m_type

=

SYS_IRQCTL;m_irq.IRQ_REQUEST

=

req;m_irq.IRQ_VECTOR

=

irq_vec;m_irq.IRQ_POLICY

=

policy;m_irq.IRQ_HOOK_ID

=

*hook_id;s

=_taskcall

(SYSTASK,

SYS_IRQCTL,&m_irq);if

(req

==

IRQ_SETPOLICY)

*hook_id

=

m_irq.IRQ_HOOK_ID;return(s);}第56页

页lib/other/taskcall.c/_taskcall

(……)int

_taskcall(who,

syscallnr,

msgptr)int

who;int

syscallnr;register

message

*msgptr;{ int

status;msgptr->m_type

=

syscallnr;status

=

_sendrec

(who,

msgptr);if

(status

!=

0)

return(status);return(msgptr->m_type);}第57页

页PUBLIC

void

sys_task()

{while

(TRUE)

{receive(ANY,

&m);call_nr

=

(unsigned)

m.m_type

-

KERNEL_CALL;caller_ptr

=

proc_addr(m.m_source);if

(!

(priv(caller_ptr)->s_call_mask

&

(1<<call_nr)))

{result

=

ECALLDENIED;}

else

if

(call_nr

>=

NR_SYS_CALLS)

{result

=

EBADREQUEST;}

elseresult

=

(*call_vec[call_nr])(&m);}…………} /*

end

of

while(true)

*/}第58页

页kernel/system.c/sys_task()PUBLIC

int

do_irqctl(m_ptr)register

message

*m_ptr;{

……case

IRQ_ENABLE:case

IRQ_DISABLE:……if

(m_ptr->IRQ_REQUEST

==

IRQ_ENABLE)enable_irq(&irq_hooks[irq_hook_id]);elsedisable_irq(&irq_hooks[irq_hook_id]);break;…………}第59页

页kernel/system/do_irqctrl.c/

do_irqctl(m_ptr)时钟中断的处理第60页

页IDT的中断门描述符的偏移地址指向了kernel/mpx386.s定义的中断入口点。.align

16_hwint00:!

Interrupt

routine

for

irq

0

(the

clock).hwint_master(0).align

16_hwint01:!

Interrupt

routine

for

irq

1

(keyboard)hwint_master(1).align

16_hwint02:!

Interrupt

routine

for

irq

2

(cascade!)hwint_master(2)……

……

……时钟中断的处理第61页

页#define

hwint_master(irq)

\/*

save

interrupted

process

state

*/;\/*

irq_handlers[irq]

*/;\/*

intr_handle(irq_handlers[irq])

*/;\;\*/;\;\;\callpushcallpopcmpjz

inborboutbsave(_irq_handlers+4*irq)_intr_handleecx(_irq_actids+4*irq),

00fINT_CTLMASKal,

[1<<irq]INT_CTLMASK/*interrupt

still

active?;\/*

getcurrentmask*//*

maskirq*//*

disable

the

irq*/;\0:movb;\al,

END_OF_INToutbINT_CTLret/*

reenable

master

8259/*

restart

(another)process*/;\*/调用统一的中断处理函数kernel/mpx386.x/hwint_master(irq)时钟中断的处理第62页

页kernel/i386.c/intr_handle(hook)调用中断处理结构链表上的一个处理函数。PUBLIC

void

intr_handle(hook)irq_hook_t

*hook;{/*

Call

list

of

handlers

for

an

IRQ.

*/while

(hook

!=

NULL)

{irq_actids[hook->irq]

|=

hook->id;if

((*hook->handler)(hook))

irq_actids[hook->irq]

&=

~hook->id;hook

=

hook->next;}}第63页

页中断向量的初始化int_gate(vec_nr,offset,dpl_type)填充一个中断描述符。prot_init()初始化中断向量表gate_table[]数组{

s_call,

SYS386_VECTOR,

USER_PRIVILEGE

}IDT的的设置for

(gtp

=

&gate_table[0];gtp

<

&gate_table[sizeof

gate_table

/

sizeof

gate_table[0]];++gtp)

{int_gate(gtp->vec_nr,(vir_bytes)

gtp->gate,PRESENT

|

INT_GATE_TYPE

|

(gtp->privilege

<<

DPL_SHIFT));}第64页

页第65页

页第66页

页第67页

页2.10.6

系统任务第68页

页用户进程调用系统服务的过程用户进程首先通过内核向服务进程发消息。服务进程处理之后,向系统任务进程发消息服务进程再通过内核向用户进程返回消息第69页

页fork()系统调用过程

(1)第70页

页在用户程序中调用lib/posix目录中_fork.c中的fork()函数fork()调用在lib/other/syscall.c/_syscall

(who,

syscallnr,

msgptr)_syscall

调用lib/I386/rts/ipc.s/_sendrec(who,msgptr)_sendrec通过系统调用中断(0x33)进入内核。_sendrec调用系统调用,进入kernel/mpx386.s

_s_call_s_call

掉用kernel/proc.c/sys_call

(call_nr,

src_dst,

m_ptr)sys_call根据参数mini_send(caller_ptr,

src_dst,

m_ptr,

flags)向PM发送消息阻塞发送进程mini_receive(caller_ptr,

src_dst,

m_ptr,

flags);让发送进程等待Pm的响应消息fork()系统调用过程

(2)第71页

页在PM

中main.c/main()get_work();receive(ANY,&m_in)

其它进程给它发消息。result

=

(*call_vec[call_nr])();servers/pm/forkexit.c/do_fork()填写进程控制块sys_fork(who,child_nr);

给内核发消息lib/sysysutil/_taskcall(who,

syscallnr,

msgptr)_sendrec

(who,

msgptr);tell_fs(FORK,

who,child_nr,

rmc->mp_pid);

给文件系统法消息PM的数据结构第72页

页PM维护进程表

mproc[NR_PROCS]全局变量输入消息m_in调用者who系统调用号callnr已用的进程数procs_in_use当前请求调用的进程MP空闲内存链表hole_headphy_clicksh_basephy_clicksh_lenhole*

h_nextphy_clicksh_basephy_clicksh_lenhole*

h_nextphy_clicksh_basephy_clicksh_lenhole*

h_nextmem_mapmp_seg[3]mp_exitstatusmp_sigstatusmp_pidmp_child_utimemp_parentmp_child_stimemp_flags012NR_PROCS-1............impmp_replymem_virmem_physmem_lenhole_headmem_virmem_physmem_lenmem_virmem_physmem_lenMp_seg[T]Mp_seg[D]Mp_seg[S]PM—fork第73页

页1、PM每接收到新消息,设置全局变If(Receive(ANY,message));M_in=message;Callnr=m_in.m_type;Who=m_in.m_source;Mp=&mproc[who];phy_clicksh_basephy_clicksh_lenhole*

h_nextphy_clicksh_basephy_clicksh_lenhole*

h_nextphy_clicksh_basephy_clicksh_lenhole*

h_nextmem_mapmp_seg[3]mp_exitstatusmp_sigstatusmp_pidmp_child_utimemp_parentmp_child_stimemp_flags012NR_PROCS-1............impmp_replymem_virmem_physmem_lenhole_headmem_virmem_physmem_lenmem_virmem_physmem_lenMp_seg[T]Mp_seg[D]Mp_seg[S]分析callnr=FORK,执行*callvec[callnr]创建进程。If(Procs_in_use==NR_PROCS) Return(EFULL);统计当前进程mp的数据段开始

至栈段结束内存大小total_size,遍历hole_head链表找到hole=min{hole:hole.hlen>=total_size},分配这块内存并进行数据拷贝。PM—fork第74页

页2、寻找

i=min{i:mproc[i].mp_flags&IN_USE==0};分配mproc[i]给子进程;*mproc[i]=*mp复制进程控制块;proc_in_use++;phy_clicksh_basephy_clicksh_lenhole*

h_nextphy_clicksh_basephy_clicksh_lenhole*

h_nextphy_clicksh_basephy_clicksh_lenhole*

h_nextmem_mapmp_seg[3]mp_exitstatusmp_sigstatusmp_pidmp_child_utimemp_parentmp_child_stimemp_flags012NR_PROCS-1............impmp_replymem_virmem_physmem_lenhole_headmem_virmem_physmem_lenmem_virmem_physmem_lenMp_seg[T]Mp_seg[D]Mp_seg[S]分析callnr=FORK,执行*callvec[callnr]创建进程。If(Procs_in_use==NR_PROCS)Return(EFULL);统计当前进程mp的数据段开始

至栈段结束内存大小total_size,遍历hole_head链表找到hole=min{hole:hole.hlen>=total_size},分配这块内存并进行数据拷贝。PM—fork第75页

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论