JOS是微内核还是单内核?分别说一下这两个的优缺点?

JOS是微内核。
单内核 monolithic kernel

单内核是指操作系统内核是一个完成了各种事情的大的程序,

  1. Linux,Unix,XV6
  2. 内核提供了功能强大的抽象,提供例如文件系统这样一个极其复杂的组件,并且将文件,目录,文件描述符作为文件系统的接口,而不是直接将磁盘硬件作为接口暴露给应用程序。
抽象的好处
  1. 可移植,在不修改任何应用程序的前提下,将他们运行在各种硬件上。
  2. 向应用程序隐藏复杂性:只需要对文件描述符调用read/write,读写磁盘上的文件系统 由 XV6内核 非常复杂的代码来实现
  3. 帮助管理共享资源:由内核来跟踪哪些内存空闲,由内核来跟踪哪些磁盘空闲,提供健壮性和安全性
  4. 所有的内核子系统,例如文件系统,内存分配,调度器,虚拟内存系统都是集成在一个巨大的程序中的一个部分,这意味着它们可以访问彼此的数据结构,进而使得依赖多个子系统的工具更容易实现
  5. 内核的所有代码都以完整的硬件权限在运行。整个XV6都运行在Supervisor mode,这意味着你可以读写任意内存地址,并且所有的内核代码都以最大的权限在运行。Linux操作系统也是这样。
单内核缺点(为什么不在所有的场合使用monolithic kernel呢?)
  1. 第一个原因是它们大且复杂。Linux总是有数十万到数百万行代码。Linux的一部分可以查看Linux的另一个部分的数据,的确使得编程更加容易,但是同样也使得内部代码有大量的交互和依赖。如果你使用了大的内核,你不可避免的会遇到Bug和安全漏洞。
  2. 它们倾向于发展成拥有所有的功能,使得Linux非常的通用,通用就意味着慢。对于各种不同的场景都能支持,或许就不能对某些特定场景进行优化。例如,你从一个进程向一个Pipe写一个字节传输到另一个进程,即使在XV6这样一个简单的内核中,都有大量的指令需要被执行。这里有buffering,locking,或许在Pipe的读写中有sleep/wakeup,或许有线程调度导致context switching,对于从一个进程移动一个字节到另一个进程来说,这里有大量的内容或许并不是必须的。
  3. 单内核大,会削弱一些复杂的抽象能力。举个例子,在Unix中,你可以wait子进程,比如说你fork出来的子进程,但是你不能wait其他进程(注,详见13.7),或许你会想要wait孙子进程或者一个不相关的进程,但是这是不可能的。或许你会想要更改其他进程的地址空间,比如说替其它受你控制的进程调用mmap,但是这也不可能。mmap只能修改你自己的地址空间,但是不能修改其他进程的地址空间。或许你是个数据库,你在磁盘上有B树索引,你或许知道很多快速展开B树的方法,但是当你读写文件系统中的文件时,文件系统并不知道你正在读写一个B树,以及如何更快的在磁盘上展开B树。所以如果你是个数据库的话,你或许很高兴文件系统可以任你摆布,但是文件系统并不会按照你想要的方式工作。以上就是内核中需要考虑的设计。
  4. 单内核不支持可扩展性(Extensibility)。应用程序或许想要实时更改内核,比如说向内核下载代码并更改内核的工作方式,这样数据库或许就可以更改数据在磁盘上的分布方式。至少在10年前,monolithic kernel没有任何功能可以支持这里的Extensibility,你只能使用内核提供的能力。
微内核

微内核的核心就是实现了IPC(Inter-Process Communication)以及线程和任务的tiny kernel。所以微内核只提供了进程抽象和通过IPC进程间通信的方式,除此之外别无他物。任何你想要做的事情,例如文件系统,你都会通过一个用户空间进程来实现,完全不会在内核中实现。

整个计算机还是分为两层,下面是kernel,上面是用户空间。在用户空间或许还是会有各种各样常见的程序:应用程序、文件系统、磁盘驱动、网络协议栈、虚拟内存系统。

内核干什么?

  1. 在内核中唯一需要做的是支持进程/任务/线程,以及支持IPC来作为消息的传递途径,
  2. 除此之外,内核不用做任何事情。内核中没有任何文件系统,没有任何设备驱动,没有网络协议栈,所有这些东西以普通用户进程在运行。
  3. 所以这提供给你一种非常小的内核,以及相对少的代码去优化,你可以优化IPC,除此之外也没有别的东西了。
什么时候用微内核?

在一些专门为某种功能设计的计算机中,需要使用某种操作系统,而你又不需要Linux带来的复杂性。(构建一些小得多且专注得多的设计)

在今天仍然有使用微内核的场景。实际上,L4微内核就有很多很多的运行实例,它用在很多手机中用来控制手机的射频,在最近的iphone中的一个旁路处理器中,也使用了L4微内核来隐藏加密密钥。所以在一些微型嵌入式系统中,微内核能够胜出,比如说在一些专门为某种功能设计的计算机中,你需要使用某种操作系统,而你又不需要Linux带来的复杂性。

微内核中的用户进程通过IPC通信的方式被广泛采用,这在很多操作系统都存在。例如我现在运行的macOS,它就是一个普通的monolithic kernel,它也很好的支持用户进程通过IPC进行通信。所以用户进程通过内核内的IPC相互通信,这是一个成功的思想并且被广泛采用。

人们构建微内核的动机是什么?

人们期望微内核:

    1. 优雅:构建一些小得多且专注得多的设计
    2. 安全,现实中至少有一种经过验证是安全的微内核系统:seL4
    3. 少量代码的程序比巨大的程序更容易被优化
    4. 运行速度快
    5. 设计限制少得多,使得APP设计灵活

微内核支持:

    1. 代码模块化:将单内核位于内核中的函数和功能,微内核将他们拆分,放在用户空间的不同部分运行,使代码模块化。
    2. 易于定制化:因为用户空间的代码更易于修改、调整、替换。
    3. 健壮:内核出错panic重启,但是将功能放在用户空间运行,出现故障的时候只有这个服务崩溃,只需要重启这一个,对驱动来说尤其明显。
    4. 可以在微内核上模拟/运行多个OS
L4微内核简介?

L4必然不是最早的微内核,但是从1980年代开始,它是最早一批可以工作的微内核之一,并且它非常能展现微内核是如何工作的。在许多年里面它一直都有活跃的开发和演进。L4有15-20个变种,有一些从1980年代开始开发的项目现在还存在。

  1. L4是微内核简单,它只有7个系统调用,虽然其中有一些稍微有点复杂,但是它还是只有7个系统调用。然而现在的Linux,有大概350个系统调用。甚至XV6这个极其简单的内核,也有21个系统调用。从这个指标来看,L4更加简单。
    1. Threadcreate系统调用,即可以创建线程,又可以创建Task。
    2. Send/Recv IPC系统调用。
    3. Mapping系统调动可以映射内存Page到当前Task或者其他Task的地址空间。
    4. Privileged Task可以将硬件控制寄存器映射到自己的地址空间,所以L4并不知道例如磁盘或者网卡的设备信息,但是实现了设备驱动的用户空间软件可以直接访问设备硬件。
    5. L4可以将任何一个设备的中断转换成IPC消息。这样,运行设备驱动的Task不仅可以读写了设备,并且也可以设置L4将特定设备的中断通过IPC消息发送给自己。
    6. 一个Task可以设置L4内核通知自己有关另一个Task的Page Fault。所以如果一个Task发生了Page Fault,L4会将Page Fault转换成一个IPC消息,并发送给另一个指定的Pager Task。每一个Task都有个与之关联的Pager Task用来处理自己相关的Page Fault。这就是关联到Page Fault的方法,通过它可以实现类似copy-on-write fork或者lazy allocation。
  2. L4并不大,它有13000行代码,这并不多,只有Linux代码的几十分之一,所以它非常的小。
  3. L4只包含基础的抽象——task、线程、地址空间、IPC
    1. 内部有一个叫做Task或者地址空间的概念,Task包含了一些内存,地址从0开始,并且可以像进程一样执行指令。
    2. 每个Task可以有多个线程,L4会调度每个Task内的多个线程的执行,可以非常方便地用线程来作为组织程序结构的工具。
    3. L4内核知道Task,知道线程,也知道地址空间,这样你就可以告诉L4如何映射地址空间内的内存Page。
    4. 另一个L4知道的事情是IPC。每一个线程都有一个标识符,其中一个线程可以说,我想要向拥有这个标识符的另一个线程发送几个字节。
  4. L4里面不包含其他的功能,没有文件系统,没有fork/exec系统调用,除了这里非常简单的IPC之外,没有其他例如pipe的通信机制,没有设备驱动,没有网络的支持等等。任何其他你想要的功能,你需要以用户空间进程的方式提供。
  5. L4支持线程间切换。L4会完成线程调度和context switch,来让多个线程共用一个CPU。
  6. Pager,如果一个进程触发了Page Fault,通过trap走到了内核,内核会将Page Fault转换成IPC消息并发送到指定的Pager Task,并告诉Pager Task是哪个线程的哪个地址触发了Page Fault。在Pager Task中,如果它实现了lazy allocation,那么它会负责从L4分配一些内存,向触发Page Fault的Task发送一个特殊的IPC,来恢复程序的运行。所以Pager Task实现了XV6或者Linux在Page Fault Handler中实现的所有功能。如果你想的话,你可以在Pager Task中实现copy-on-write fork或者memory mapped files,Pager Task可以实现基于Page Fault的各种技巧。这是类似L4的微内核相比传统的内核,对于用户程序要灵活的多的众多例子之一。如果Linux并没有copy-on-write fork,并且你想要有这个功能,你不可能在不修改内核的前提下完成这个功能。Linux中很难写一些可移植的用户空间代码来实现copy-on-write fork。然而,在L4里面,这就相对简单了。L4就好像是完全设计成让你去写用户空间代码来获取Page Fault,并实现copy-on-write fork。所有这些都可以在用户空间完成,而不用弄乱内核。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值