Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1078683
  • 博文数量: 104
  • 博客积分: 3715
  • 博客等级: 中校
  • 技术积分: 1868
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-30 08:38
文章分类

全部博文(104)

文章存档

2013年(1)

2012年(9)

2011年(41)

2010年(3)

2009年(3)

2008年(47)

分类: 系统运维

2011-01-06 10:11:31

** Minix3进程简介
    终于要看看minix是怎么做的了,这一节给出一个系统的概览。Minix3中唯一的进程间通信原语就是前面提到
的消息传递方式。

*** 整体结构
    总体上讲,Minix从下到上分为四个层次:内核层、驱动层、服务层和应用层。这四个层次中,只有内核层
运行在CPU的内核态,可以执行所有的指令。其它三个层次都运行在CPU的用户态,只能执行非特权指令。驱动层、
服务层和应用层进程的主要区别在于它们的权限(Minix定义的特权级别)不同,例如,驱动层可以调用访问IO
端口和中断的kernel call,而服务层不能。下面,我们依次看看这几个层次。
**** 内核层
    这是minix中唯一运行在CPU特权态下的代码。内核层分为三个部分:
    1.  kernel:该部分包括具体操作IO端口、MMU、CPU等硬件的汇编代码(封装成C调用),负责系统中所有
        进程部分状态的维护和进程切换,负责进程间通信的实现;
    2.  clock task:时钟驱动,可以看成运行在内核地址空间的一个“进程”,这个驱动只与kernel打交道,
        不对外层提供服务;
    3.  system task:另一个运行在内核空间的“进程”,它对上层提供服务,实现了一组kernel call,调用
        这些kernel call需要特权,例如,不是所有的进程都可以调用读写IO端口的kernel call。

    内核层向上层提供的接口就是这一组kernel call,用于帮助上层完成任务。kernel call其实是很底层的,
例如,读写IO端口、在不同的地址空间之间拷贝数据等,所以,minix定义了各个进程的特权,和哪些特权可以
访问哪些kernel call的规则。如果没有kernel call,很多功能无法实现在用户态进程中。
**** 驱动层
    这一层包含了除时钟以外的设备驱动,每个驱动是一个独立的进程。这些进程具有最高的特权级别,可以
调用所有的kernel call,完成硬件的管理工作。某些驱动是随内核一并加载到内存并启动的,而另一些则是
在系统起来之后启动的。
**** 服务层
    这一层包含了系统服务进程。其中一个比较有意思的是再生服务器,这个服务器启动那些不和内核一并启动
的驱动和服务,并且当某个服务/驱动出现异常时,自动重启它。这一层的服务,实现了POSIX定义的系统调用。
例如,和进程相关的绝大多数系统调用由PM实现,而与文件系统相关的绝大多数系统调用由FS实现。
**** 应用层
    这一层是特权最小的进程。包括了所有非系统进程。其中,最重要的一个可能是init进程。

*** 进程管理
**** minix3的启动过程
    启动,一般要首先找到启动介质,例如软盘、CD、硬盘、其它可移动存储设备等。当计算机找到第一个可启
动的软盘时,它会自动读取启动磁盘的第一个磁道的第一个扇区到内存,并开始执行其中的代码。这就是最初的
bootstrap代码,它通常非常小,非常简单,必须被包含在512Bytes的扇区中。Minix3的bootstrap代码的功能
是加载并启动一个更大的启动程序,boot,进而由后者加载并启动操作系统。
    从硬盘启动的话还有一个中间步骤。硬盘是分区的。硬盘的第一个磁道的第一个扇区包含一小段
程序和分区表,这个扇区称为主引导扇区(Master boot record)。当计算机找到的第一个可启动的磁盘是
一个硬盘时,就会把这个MBR扇区加载到内存并开始执行其中的代码,MBR的代码遍历分区表,并找到第一个“
活跃分区”(activate partition),加载那个分区的第一个扇区并执行其中的代码。后面的过程与前文描述的
类似。
    如果找到的可启动介质是一个CD-ROM(因为CD出现在硬盘、软盘之后,支持CD启动的计算机可以从CD读取较大
的数据块,而不仅仅是一个扇区),计算机会从CD加载一块数据,这块数据通常就是一个启动软盘的映像,加载后
作为RAM Disk使用,之后,启动过程就从这个RAM Disk开始,与软盘启动类似。

    当boot程序被执行时,它会找一个指定的启动映像文件,这个文件包括多个部分。boot将各个部分加载到
特定的内存位置。其中,内核(包括clock task和system task)、PM、FS是最重要的三个部分,另外,映像中
至少要包含一个磁盘驱动。RS必须包含在启动映像中,为了方便,Log服务、tty驱动以及Init等驱动/服务通常
也包含在映像中。

    进程树的初始化过程。内核被boot启动后,它会启动在其中的clock task和system task。
    osdi书中给出的初始化过程比较老,新的初始化过程可能和它有些不同。这里列举一下结果现象:
    进程号0不对应于任何一个进程,可见,这是一个特殊值,用于标记不存在。
    PPID为0的进程一共有四个:
    1.  -1:kernel
    2.  -2:system
    3.  -3:clock
    4.  -4:idle
    5.  1: init
    猜测前四个为负数的任务应该是内核中的任务,与前文相比多了一个idle任务,可以理解。内核启动完属于
自己地址空间的任务后,启动的第一个用户态进程是init。
    之后,我们看到,rs是init的子进程。而所有的驱动、系统服务都是rs的子进程。这应该是init通过rs的
service接口启动的。这样,当这些进程发生异常时,rs可以重启它们。
    最后,init自己也会启动一些子进程,例如cron、update、getty等,这些作为init的子进程存在。用户的
其它进程也是init进程树中的进程。
**** 问题,怎么验证上面这个猜测?
    从启动信息可见,BootImage中包含:kernel, ds, rs, pm, sched, vfs, memory, log, tty, mfs, vm,
pfs, init.
    先来看看init的rc做了什么。
***** /etc/rc分析
    这个文件就是init启动后理解开始执行的文件
    1.  重定向,stdout和stderr都打印到/dev/log下,stdin是/dev/null;
    2.  设置TERM、PATH、RC_TZ、umask;
    3.  rc定义的up函数使用service启动一个指定的服务,服务一定在/sbin/下面。
    4.  rc定义的edit函数使用service的edit命令完成。
    5.  从打印消息来看,开机启动时传的action参数是start;
    6.  在rc里面,使用edit函数更新了BootImage中几个程序的配置,但是没有启动。
    7.  在/usr/etc/rc中对系统做了进一步的初始化。

    显然,那些系统的驱动和服务不是在rc里面启动的。上面的猜测是有问题的,后续再用别的方式确认。

*** Minix的IPC
    minix的IPC采用(同步的)消息传递的原语:
    1.  send(dest, &message):向目标发送一个消息;
    2.  receive(src, &message):从指定地方(或者ANY)接收一个消息;
    3.  sendrec(src_dest, &message):向目标发送一个消息,同时等待回复并接收;
    4.  notify(dest):向目标发送一个通知,非阻塞。目标的receive函数的下次调用会收到这个通知;
    注意,用户进程之间不能发送消息,但用户进程可以向服务发送消息,服务、驱动、任务之间可以发送消息。
Minix中消息的大小是固定的,在编译时就确定了。
    其实,notify是一个异步消息传递原语,为了使用方便而引入,但是对其增加了极大的限制。例如,notify
不能传递任何数据,接收者仅仅知道发出者是谁。notify仅仅用于系统进程之间,用户进程不能发出或者接收
notify等。

*** Minix3的进程调度
    其实,中断是保证一个多任务操作系统运行的最为基本的动力。中断可以是硬件中断,也可以是软件中断,
例如,sendrec调用就会产生一个软中断,其处理过程与硬件中断非常类似。
    MINIX3使用多队列的调度器。clock任务和system任务的优先级最高,之下是驱动,之下是服务,之下是
用户进程,之下是IDLE任务(在没有其它任务/进程可以运行时,运行它)。
    优先级队列不是唯一控件调度的,在minix中,每个进程分配得到的时间片的大小是不同的。用户进程的时间
片通常较小,而服务、驱动的时间片通常较大。
    调度算法描述如下:
    1.  调度器的调度时机如前文所述,在每次调度时,会挑选优先级最高的队列头的进程运行;
    2.  如果一个进程用完了它所有的时间片而被中断,并且该进程又是上一次被执行的进程,那么
        这个进程会被放到一个更低的优先级队列的队尾,如此继续,保证一个进程不会阻塞其它所有的进程;
    3.  如果一个进程用完了它所有的时间片,但是它没能获得再次被调度执行(其它进程被调度了),那么它会被
        调高到更高的优先级队列的队尾;
    4.  在同一个队列中,调度器采用RR的调度算法。另外,调度器会照顾IO密集型进程。如果某个进程是由于
        等待IO而被阻塞的(此时,时间片还没用完),当IO可用时,这个进程会被插入到所在队列的队头,其时间
        片就是上次剩下的时间片。

** Minix3进程的实现

*** 源文件布局
    源文件布局。Minix3的源文件大部分使用了相对路径,可以随意移动。但是,只有C头文件使用了两个固定
的路径:/usr/src/include目录,这个目录保存了头文件的主拷贝。在每次Make的时候,会删除/usr/include目录
而把/usr/src/include目录拷贝到/usr/include,后者是编译器查找头文件的默认目录。
    在/include目录下,包含了POSIX标准的头文件,此外,还有几个重要的子目录:
    sys/    该目录下也是POSIX标准的头文件
    minix/  该目录下是minix操作系统的头文件
    arch/   该目录下是机器定义相关的头文件,当前只包含i386子目录

    在/include目录下,还包括其它一些头文件和子目录,它们对系统上某些应用的运行有用,但不是编译
基本minix系统必须的,例如arpa,net,netinet/三个子目录包含了TCP/IP网络相关的一些头文件。
    src/下另外一些必须的目录列举如下:
    kernel/ 包含了第一层的,处于内核态的代码。如调度、时钟任务、系统任务等;
    drivers/    包含了第二层,驱动;
    servers/    包含了第三层,系统服务;

    lib/    系统库
    tools/  编译MINIX3的工具、脚本
    boot/   启动引导代码
    以上的目录是编译一个MINIX3系统必须的,下面是另外一些额外支出的目录:
    test/   包含了测试代码
    commands/   包含了常用工具、应用程序的代码,如cp、ls等;

*** 启动映像加载后的内存映像
    0.  0~1K的地址是中断向量,1K~2K的地址被BIOS使用;
    1.  kernel会被加载到低端内存,从2K地址处开始;
        -----空闲空间----
    2.  boot monitor在一开始被加载到590K~640K的地址处;
        -----对Minix3不可用空间,经典的640K~1024K的断开区间----
    3.  从1M开始顺序加载启动映像中其它的部分,如pm、fs、rs...init
        -----空闲空间----

    后续,应用程序启动后会使用空闲空间(优先使用内核上面的低端内存)。

阅读(3028) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~