前言
2.1 需求和设计目标
回到1989年,下面的需求驱动了Windows NT的规范:
- 提供一个真正32位的、抢占式的(preemptive)、可重入的(reentrant)虚拟内存操作系统。
在多种硬件体系架构和平台上运行。 - 可在对称多处理器系统(symmetric multiprocessing systems)上运行,并且能很好地适应处理器的数量。
- 成为一个极好的分布式计算平台,无论是作为网络客户机还是服务器。
- 能够运行大多数己有的16位MS-DOS和Microsoft Windows3.1应用程序。
- 符合政府对于POSIX1003.1兼容性的要求。
- 符合政府和工业界对于操作系统安全性方面的要求。
- 支持Unicode,从而很容易适应全球市场。
要创建一个满足这些需求的系统,必须做出数千个决定:
为了便于做出这些决定, Windows NT设计小组在项目开始之初选择了下面的设计目标:
扩展性
:编写的系统代码必须能够随着市场需求的变化而自如的增长和改变可移植性
:系统必须能运行在多种硬件体系架构上,必须能根据市场的需要,相对容易的迁移到新的体系架构上可靠性和健壮性
系统应该能保护自己,不会因内部故障和外部篡改而不能工作,应用程序应该无法伤害操作系统或其他应用程序兼容性
虽然Windows NT应该扩展已有的技术,但是它的用户界面和API应该与老版本Windows和MS-DOS兼容。而且它也应该能与其他的系统,比如Unix OS2 NetWare 很好的互操作.性能
在每一种硬件平台上尽可能运行得更快,对外部的响应尽可能地及时.
2.2 操作系统模型
两种模式:
- 用户模式
- 内核模式
用户模式和内核模式
在大多数多用户操作系统中,应用程序与操作系统本身是隔离的——操作系统内核代码运行在处理器的特权模式下 (在本书中称为内核模式, kernel mode
),可以访问系统数据和硬件;
应用程序代码运行在处理器的非特权模式下(称为用户模式,usermode
),只有很有限的一组接口可以使用,对系统数据的访问受到限制,并且无法直接访问硬件。当用户模式程序调用系统服务时,处理器执行一条特殊的指令,将调用线程切换到内核模式。当该系统服务完成时,操作系统将线程环境切换回用户模式,允许调用者继续执行。
内核保护机制
与大多数 UNIX 系统类似, Windows 是一个庞大而完整的操作系统; 操作系统的大部分代码与设备驱动程序代码共享同样的受保护的内核模式内存空间。这意味着,操作系统的任一组件或者设备驱动程序都有可能破坏其他系统组件所使用的数据。
然而, Windows 实现了一些内核保护机制, 比如 Patch Guard
和内核模式代码签名
(这两种机制都在第 3 章“系统机制”中介绍),它们有助于减缓或避免与“共享内核模式地址空间”有关的问题发生
。
当然,操作系统的所有组件都是完全受保护的,不会被错误的应用程序破坏,因为应用程序不能直接访问操作系统中特权部分的代码和数据(不过,它们可以快捷地调用其他的内核服务)。
Windows 无论是作为应用服务器,还是工作站平台,从操作系统核心服务(比如虚拟内存管理、文件 I/O、网络,以及文件和打印共享)的角度来看,它都很快地赢得了健壮性和稳定性两方面的良好声誉,之所以如此,对操作系统组件的这种保护是原因之一。
内核模式组件的面向对象
Windows 的内核模式组件也体现了基本的面向对象设计原则。
例如,它们通常并不会直接进入另一个组件的数据结构来访问该组件所维护的信息,而是使用正式的接口来传递参数,以及访问和/或修改相应的数据结构。
虽然 Windows 内部普遍使用了对象来表达共享的系统资源,但是,从严格意义上讲,Windows 并不是一个面向对象的系统。出于移植性的考虑,Windows 操作系统的大多数代码是用 C 语言编写的。
C 语言并不直接支持面向对象的语法元素,比如数据类型的动态绑定、多态函数或者类继承等。
因此,Windows 中基于 C 语言的对象实现只是借用了(但并不依赖于) 特定的面向对象语言的特性。
2.3 系统架构
基本架构
在图 2.1 中,首先可注意到中间有一条线把 Windows 操作系统的用户模式和内核模式两部分划分开来。线上面的方框代表了用户模式的进程,线下面的组件是内核模式的操作系统服务。正如在第 1 章“概念和工具”中提到的,用户模式的线程在一个受保护的进程地址空间中执行(不过,当它们在内核模式中执行时,它们可以访问系统空间)。
因此,系统支持进程、服务进程、用户应用程序和环境子系统都有它们各自的私有进程地址空间。
用户模式进程的基本类型
用户模式进程有如下四种基本的类型。
固定的 (或者硬性指定的) 系统支持进程
(system support process), 比如登录 (logon) 进程和会话管理器 (session manager),它们并不是 Windows 服务。(也就是说,它们不是由服务控制管理器来启动的,第 4 章“管理机制”将详细地介绍 Windows 服务)。服务进程(service process)宿纳的是 Windows 服务
,比如 Task Scheduler 和 Print Spooler 服务。Windows 服务往往要求独立于用户登录而运行。许多 Windows 服务器应用,比如 Microsoft SQL Server 和 Microsoft Exchange Server,也包含了一些以 Windows 服务方式来运行的组件。用户应用程序(user application)
,可以是下面几种类型之一:Windows32 位或 64 位,Windows 3.1 16 位,MS-DOS16 位或者 POSIX32 位或 64 位。注意,16 位应用程序只能运行在 32 位 Windows 上。环境子系统服务器进程(environment subsystem server process)
实现了操作系统环境(environment)的支持部分。这里所谓的环境是指操作系统展示给用户或者程序员的个性化部分。WindowsNT 最初发布的时候带了三个不同的环境子系统:Windows、POSIX 和 OS/2。然而,POSIX 和 OS/2 子系统的最后一次发布是随 Windows 2000 一起。
Windows 客户机系统的旗舰和企业版本,以及所有的服务器版本,包含了一个增强的 POSIX 子系统,称为 UNIX 应用子系统(SUA,Subsystem for UNIX-based Applications)。
在图 2.1 中,请注意在“服务进程”和“用户应用程序”方框下面的“子系统 DLL”方框。
在 Windows 下,用户应用程序并不直接调用原生的 Windows:操作系统服务,而是通过一个或者多个子系统动态链接库 (DLL) 来发起调用。子系统 DLL 的角色是,将一个已文档化的函数转化为一些恰当的内部(通常是未文档化的)原生系统服务调用。这一转化过程可能会一一也可能不会一一向正在为用户应用程序提供服务的环境子系统进程发送消息。
Windows内核模式组件
Windows 的内核模式组件包含:
Windows 执行体 (executive)
包含了基本的操作系统服务, 比如内存管理、进程和线程管理、安全性、I/O、网络和跨进程通信。Windows 内核是由一组低层次的操作系统功能构成的, 比如线程调度 (thread scheduling) 、中断 (interrupt) 和异常分发 (exception dispatching) , 以及多处理器同步。它也提供了一组例程和基本对象,执行体的其余部分利用这些例程和对象实现更高层次的功能。设备驱动程序 (device driver)
既包括硬件设备驱动程序, 也包括像文件系统和网络驱动程序之类的非硬件设备驱动程序。其中硬件设备驱动程序将用户的 I/O 函数调用转换成特定的硬件设备 I/O 请求。硬件抽象层 (HAL, Hardware Abstraction Layer)
是指一层特殊的代码, 它把内核、设备驱动程序和 Windows 执行体的其余部分, 跟与平台相关的硬件差异 (比如不同主板的差异) 隔离开来。窗口和图形系统 (windowing and graphic system)
实现了图形用户界面 (GUI) 功能 (更为人们熟知的叫法是 Windows USER 和 GDI 两部分功能) , 比如对窗口的处理、用户界面控件,以及绘制等。
表 2.1 列出了 Windows 操作系统核心组件的文件名称。(你有必要知道这些文件名称, 因为我们将会用名称来引用某些系统文件)。本章后面部分以及后续的章节中将会详细地介绍其中的每一个组件。
可移植性
Windows 在设计时,就确定要能够运行在各种不同的硬件体系架构之上。Windowsl 的初始发行版本支持 x86 和 MPS 体系架构。稍后又加入了对 DEC (Digital Equipment Corporation,.该公司被 Compaq 收购,而 Compaq 后来又与 HP 即 Hewlett-Packard 兼并了) Alpha AXP 的支持(尽管 Alpha AXP 是一个 64 位处理器,但 Windows NT 运行在 32 位模式下。在 Windows2000 的开发过程中,一个原生的 64 位版本可以在 Alpha AXP 上运行,但是这个版本一直没有发布)。在 Windows NT3.51 中又加入了对第四种处理器架构 Motorola PowerPC 的支持。然而,由于市场需求的变化,在 Windows2000 开发前夕,对 MIPS 和 PowerPC 体系架构的支持被放弃了。后来,Compaq 又撤销了对 Alpha AXP 体系架构的支持,所以最终的结果是,Windows2000 只支持 x86 体系架构。Windows XP 和 Windows Server2003 增加了对三种 64 位处理器族的支持,它们分别是 Intel Itanium IA-64 族、AMD64 族,以及 Intel 针对 x86 的 64 位扩展技术 (EM64T,它与 AMD64 体系架构相兼容,但在所支持的指令方面略有差别)。后两种处理器族称为 64 位扩展系统 (64bit extended system),在本书中称为 x64。(关于 Windows 如何在 64 位版本中运行 32 位应用程序,第 3 章会说明。)
Windows 主要通过以下两种方法来实现可移植性,以支持多种硬件体系架构和平台:
- Windows 有一个分层设计,系统的低层部分是与处理器体系架构相关的,或者是与平台相关的,它们被隔离到独立的模块中,所以,系统的高层部分可以不考虑体系架构之间的差别,也不用关心硬件平台的差异。有两个关键的组件为操作系统提供了可移植性,它们是内核 (包含在 Ntoskrnl. exe 中) 和硬件抽象层 (或称 HAL,包含在 Hal. dll 中),本章后面将详细介绍这两个组件。与体系架构相关的功能,比如线程环境切换 (thread context switching) 和陷阱分发 (trap dispatching) 是在内核中实现的。在同样的体系架构下,不同系统之间有所差异的功能 (例如,不同的主板) 则是在 HAL 中实现的。另外还有唯一一个组件也有相当数量的代码是与体系架构相关的,那就是内存管理器,但是与整个系统相比,这仍然只是一小部分而已。
- Windows 的绝大部分代码是用 C 语言编写的,少部分是用 C++编写的。只有那些需要直接与系统硬件打交道的部分 (比如中断陷阱处理器 (interrupt trap handler)),或者对性能极端敏感的操作系统部分 (比如环境切换 (context switching)),才是用汇编语言编写的。汇编语言代码不仅出现在内核和 HAL 中,也出现在操作系统核心的其他一些地方 (比如实现了互锁指令的例程,以及本地过程调用设施中的模块),还出现在 Windows 子系统的内核模式部分,甚至在某些用户模式库中,比如 Ntdll. dll 中的进程启动代码 (本章后面将介绍系统库 Ntdll. dll)
对称多处理
多任务 (multitasking) 是指让多个执行线程共享同一个处理器的操作系统技术。然而, 当一台计算机有不止一个处理器时,它可以同时执行多个线程。因此,虽然一个多任务操作系统只不过看起来好像同一时刻可以执行多个线程,但是,一个多处理器操作系统可以真正地做到同一时刻执行多个线程,在每个处理器上执行一个线程。
正如本章开始时所提到的, Windows 的一个关键设计目标是, 必须能够很好地在多处理器计算机系统上运行。Windows 是一个对称多处理器 (SMP, symmetric multiprocessing) 操作系统。没有主处理器――操作系统和用户线程可以被调度到任何处理器上运行。而且,所有的处理器共享唯一的内存空间。这种模型与非对称多处理器 (ASMP, asymmetric multiprocessing) 不同,在一个典型的非对称多处理器操作系统中,系统选择其中一个处理器来执行操作系统内核代码,而其他的处理器只运行用户代码。这两种多处理器模型的区别如图 2.2 所示。
Windows 也支持三种现代的多处理器系统:多核、超线程和 NUMA (非一致的内存架构〔non-uniform memory architecture) ) 。在下面的段落中将简要介绍这三种多处理器系统 (有关 Windows 对这些系统的调度支持的详细完整的描述, 参见第 5 章“进程、线程和作业”中的“线程调度”一节)。
超线程 (Hyper-Threading)
是 Intel 引入的一项技术, 它可以在每个物理核上提供多个逻辑处理器。每个逻辑处理器有自己的 CPU 状态, 但是执行引擎和片上缓存则是共享的。这使得一个逻辑 CPU 可以在其他逻辑 CPU 停转 (比如缓存未命中, 或者分支预测错误) 的时候继续执行。
调度算法已经被改进过了,因而可以最佳地利用支持超线程的机器,例如,原来的做法是,将线程调度到一个空闲的物理处理器上,现在则改进为“选择一个物理处理器上的空闲逻辑处理器 (该处理器的其他逻辑处理器可能正忙着)”。有关线程调度的更多细节,参见第 5 章。
在 NUMA 系统中, 处理器被组织成更小的单元, 称为节点 (node)
。
每个节点有它自己的处理器和内存, 并且通过一个缓存一致 (cache-coherent) 的互连总线连接到更大的系统上。
NUMA 系统上的 Windows 仍然作为一个 SMP 系统来运行, 其中所有的处理器可以访问所有的内存一一只不过,节点本地的内存访问起来比其他节点的内存更快一些而已。系统提高性能的做法是,根据线程用到的内存所在的节点,将线程调度到同一节点中的处理器上。系统尽可能地在节点内部满足内存申请的请求,只有在必要的时候才从其他的节点分配内存。
很自然, Windows 也支持多核系统――因为这些系统有多个真正的物理核 (只是在同一个芯片上) , Windows 中原来的 SMP 代码将这些核看作单独的处理器, 但是, 一些特定的需要记录和标识核的任务 (比如许可管理,稍后讲述) 例外,这些任务需要区分是同一个处理器的核,还是不同插槽上的核。
Windows 最初设计的时候并没有特定的处理器个数限制,只是不同的许可策略使 Windows 的不同发行版本有了差异。然而,为了方便和高效起见,Windows 用一个位掩码(有时候称为亲和性掩码 (af 衎 inity mask)) 来记录和跟踪处理器(总数、空闲、忙,或诸如此类的细节),这里位数与机器的原生数据类型 (32 位或 64 位) 相同,因而使得处理器可以直接在一个寄存器里操纵这些位。由于这个原因,Windows 系统最初限定了 CPU 的个数在一个原生字的范围内,因为亲和性掩码不可能任意增长。为了保持兼容性,以及支持具有更多处理器的系统,Windows?实现了一个更高级的概念,称为处理器组 (processor group)。处理器组是指可以由一个亲和性掩码来定义的一组处理器,内核和应用程序在更改亲和性设置的过程中可以选择它们将使用哪一组。应用程序为保持兼容,可以查询当前系统支持多少组(目前限制 4 组),然后枚举出每个组的位掩码。同时,老的遗留下来的应用程序继续工作,它们只会看到它们当前所在的组。关于 Windows 如何把处理器分配到组的确切细节(与 NUMA 有关),参见第 5 章。
如前所述,实际许可支持的处理器数目取决于所用的 Windows 发行版本(参见后面的表
2.2)。该数值作为策略值“Kernel–RegisteredProcessors”存放在系统许可策略文件中 (\Windows\ServiceProfiles\NetworkService\AppData\Roaming Microsoft\SoftwareProtectionPlatf orm\tokens… dat)。(记住,篡改此数据将违反软件许可规定,而且,通过修改许可策略来使用更多的处理器,涉及更多的工作,不仅仅是修改这个值。)
可伸缩性
多处理器系统的一个关键问题是可伸缩性 (scalability)。
为了在一个 SMP 系统上正确地运行,操作系统的代码必须遵守严格的指示和规则。
在多处理器系统中,资源竞争和其他性能问题比在单处理器系统中要复杂得多,而且必须在系统设计的时候就考虑清楚。
Windows 集下面几个特性于一身,这些特性对于 Windows 作为一个多处理器系统的成功起到了至关重要的作用:
- 能够在任何可用处理器上运行操作系统代码,也可以同时在多个处理器上运行系统代码。
- 在单个进程内执行多个线程,每个线程可以在不同的处理器上并行地执行。
- 内核内部的细粒度同步(比如自旋锁、排队的自旋锁,以及推锁,这些将在第 3 章详述),以及在设备驱动程序和服务器进程内部的细粒度同步,这使得更多的组件可以在多个处理器上并发地运行。
- 诸如IO 完成端口 (I/O completion port)(在本书下册第 8 章“I/O 系统”中介绍) 之类的编程机制,使得可以实现高效的多线程服务器进程,并且这样的进程在多处理器系统上有很好的可伸缩性。
Windows 内核的可伸缩性一直在不断进步。比如, Windows Server 2003 使用了针对每个 CPU 的调度队列, 这使得可以在多个处理器上并行地进行线程调度决策。Windows 7 和 Windows Server 2008R 2 消除了调度数据库的全局锁。这样的关于锁粒度的逐步改进也出现在其他的区域,比如内存管理器。有关多处理器同步的进一步细节可以在第 3 章中找到。
客户机和服务器版本之间的差异
Windows 既发行客户机版本,也发行服务器版本的零售软件包。截止到本书写作时, Windows 7 有 6 个客户机版本: Windows 7 Home Basic、 Windows 7 Home Premium、 Windows 7Professional、 Windows 7 Ultimate、 Windows 7 Enterprise 和 Windows 7 Starter。
Windows Server 2008 R2 有 7 个不同版本: Windows Server 2008 R2 Foundation, Windows Server 2008 R2 Standard. Windows Server 2008 R2 Enterprise. Windows Server 2008 R2 Datacenter Windows Web Server 2008 R2. Windows HPC Server 2008 R2,以及 Windows Server 2008 R2 for Itanium-Based Systems (这是最后一个支持 Intel Itanium 处理器的 Windows 发行版)。
此外,客户机版本还有一种“N”版本,它们不包含 Windows Media Player。最后,Windows Server 2008 R2 的 Standard、 Enterprise 和 Datacenter 版本还有相应的“Hyper-V”版本,即包含 Hyper-V. (第 3 章中将讨论 Hyper-V 虚拟化。)
这些版本在以下方面有所不同:
- 所支持的处理器的数目(指的是插槽,不是核或线程)。
- 所支持的物理内存的数量(实际是指最高可用的 RAM 物理地址–关于物理内存限制的更多信息,参见本书下册第 10 章)。
所支持的并行网络连接的数量(例如,在客户机版本中,至文件和打印服务的并发连接数最多为 10 个)。
支持媒体中心(Media Center)。 - 支持多点触摸(Multi-Touch)、Aero 和桌面合成(Desktop Compositing)。
- 对于诸如 BitLocker、VHD 引导、AppLocker、Windows XP 兼容模式等特性的支持,另外还有 100 多个可配置的许可策略值。
Windows Server 版本附带的分层的服务(layered service),并不包含在客户机版本中(例如目录服务和集群服务)。
表 2.2 列举了 Windows 7 和 Windows Server 2008 R2 在内存和处理器支持方面的不同。关于 Windows Server 2008 R2 不同版本之间的详细比较,请参考 www.microsoft.com/windowsserver
2008/en/us/r2-compare-specs. aspx。
虽然 Windows 操作系统有多个客户机和服务器零售软件包,但是它们共享同一组核心系统文件,包括内核映像 Ntoskrnl. exe(以及 PAE 版本 Ntkmnlpa. exe)、HAL 库、设备驱动程序,以及基本的系统辅助工具和 DLL。这些文件对于 Windows 7 和 Windows Server 2008 R2 的所有发行版都是相同的。