需求和设计目标
Windows NT设计小组在项目开始之初选择了下面的设计目标:扩展性、可移植性、可靠性和健壮性、兼容性、性能。
操作系统模型
大多数多用户操作系统中,应用程序与操作系统本身是隔离的。当用户模式程序调用系统服务时,处理器执行一条特殊的指令,将调用线程切换到内核模式。当该系统服务完成时,操作系统将线程环境切换回用户模式,允许调用者继续执行。
与大多数Unix类似,Windows是一个庞大而完整的操作系统:操作系统的大部分代码与设备驱动程序代码共享同样的受保护的内核模式内存空间。这意味着,操作系统的任一组件或者设备驱动程序都有可能破坏其他系统组件所使用的数据。然而,Windows实现了一些啮内核保护机制,有助于减缓或避免与“共享内核模式地址空间”有关的问题发生。
当然,操作系统的所有组件都是完全受保护的,不会被错误的应用程序破坏,因为应用程序不能直接访问操作系统中特权部分的代码和数据(不过可以快捷的调用其他的内核服务)。
Windows的内核模式组件也体现了基本的面向对象设计原则。
总体结构
用户模式进程有如下四种基本类型:固定的(或者硬性指定的)系统支持进程,比如登录进程和会话管理器;服务进程宿纳的是Windows服务,Windows服务往往要求独立于用户登录而运行;用户应用程序;环境子系统服务器进程,实现了操作系统环境的支持部分,这里所谓的环境是指操作系统展示给用户或者程序员的个性化部分。
在Windows下,用户应用程序并不直接调用原生的Windows操作系统服务,而是通过一个或者多个子系统动态链接库来发起调用。子系统DLL的角色是,将一个已文档化的函数转化为一些恰当的内部(通常是未文档化)原生系统服务调用。
Windows内核模式组件包含:Windows执行体包含了基本的操作系统服务,比如内存管理、进程和线程管理、安全性、I/O、网络和跨进程通信;Windows内核是由一组低层次的操作系统功能构成的,比如线程调度、中断和异常分发,以及多处理器同步,也提供了一组例程和基本对象;设备驱动程序 ,既包括硬件设备驱动程序,也包括像文件系统和网络驱动程序之类的非硬件设备驱动程序;硬件抽象层(HAL)是指一层特殊的代码,它把内核、设备驱动程序和Windows执行体的其余部分,跟与平台相关的硬件差异隔离开来;窗口和图形系统实现了图形用户界面功能,比如对窗口的处理、用户界面控件以及绘制等。
可移植性。Windows有一个分层设计,系统的低层部分是与处理器体系架构相关的,或者是与平台相关的,它们被隔离到独立的模块中,所系,系统的高层部分可以不考虑体系架构之间的差别,也不用关心硬件平台的差异。内核和硬件抽象层为操作系统提供了可移植性。与体系架构相关的功能是在内核中实现的,在同样的体系架构下,不同系统之间有所差异的功能则是在HAL中实现的。
对称多处理(SMP)。多任务是指让多个执行线程共享同一个处理器的操作系统技术。然而,当一台计算机不止一个处理器时,可以同时执行多个线程。Windows设计的一个关机目标是,必须能够很好的在多处理器计算机系统上运行。Windows是一个对称多处理器操作系统。没有主处理器——操作系统和用户线程可以被调度到任何处理器上运行。而且,所有的处理器共享唯一的内存空间。这种模型与非对称多处理器不同。
超线程是Intel引入的一项技术,它可以在每个物理核上提供多个逻辑处理器,每个逻辑处理器都有自己的cpu状态,但是执行引擎和片上缓存则是共享的。这使得一个逻辑CPU可以在其他逻辑CPU停转的时候继续执行。调度算法已经被改进过了,因而可以最佳的利用支持超线程的机器。
在NUMA系统中,处理器被组织成更小的单元,称为节点。每个节点有它自己的处理器和内存,并且通过一个缓存一致的互连总线连接到更大的系统上。NUMA系统上的Windows仍然作为一个SMP系统来运行,其中所有的处理器都可以访问所有的内存,只不过,节点本地的内存访问起来比其他节点的内存更快一些而已。
Windows用一个位掩码(有时候称为亲和性掩码)来记录和跟踪处理器,这里位数与机器的原生数据类型相同,因而使得处理器可以直接在一个寄存器里操纵这些。由于这个原因,Windows系统最初限定了CPU个数在一个原生字的范围内,因为亲和性掩码不能任意增长。为了保持兼容性,以及支持具有更多处理器的系统,Windows实现了一个更高级的概念,称为处理器组,处理器组是指可以由一个亲和性掩码来定义的一组处理器,内核和应用程序在更改亲和性设置的过程中可以选择它们将使用哪一组。
可伸缩性。多处理器系统的一个关键问题是可伸缩性。为了在一个SMP系统上正确地运行,操作系统的代码必须遵守严格的指示和规则。Windows集下面几个特性于一身,这些特性对于Windows作为一个多处理器系统的成功起到了至关重要的作用:能够在任何可用处理器上运行操作系统代码,也可以同时在多个处理器上运行系统代码;在单个进程内执行多个线程,每个线程可以在不同的处理器上并行执行;内核内部的细粒度同步,以及在设备驱动程序和服务器进程内部的细粒度同步,这使得更多的组件可以在多个处理器上并发的运行;诸如I/O完成端口之类的编程机制,使得可以实现高效的多线程服务器进程,并且这样的进程在多处理器系统上有很好的可伸缩性。
关键的系统组件
环境子系统和子系统DLL。环境子系统的角色是,将基本的Windows执行体系统服务的某个子集暴露给应用程序。每个子系统都提供了对于Windows原生服务的一个不同子集的访问能力。每个可执行映像都被绑定到一个且唯一的子系统上。映像文件运行时,负责创建进程的代码会检查该映像头部的子系统类型代码,所以可以通知正确的子系统,有新的进程被创建。
当应用程序调用子系统DLL中的某个函数时,可能会发生下述三件事情之一:该函数完全是在该子系统DLL中实现的,在用户模式下运行;该函数要求调用Windows执行体一次或者多次;该函数要求在环境子系统进程中完成某些工作(环境子系统进程运行在用户模式下,负责维护那些在其控制下运行的客户应用程序的状态)。有些函数可以是以上列出的第2和第3项的组合。
子系统启动。子系统由会话管理器进程启动起来的,子系统的启动信息保存在注册表键HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Subsystems的下面。Required值列出了系统引导时加载的子系统。Optional值表明了SUA子系统将会按需启动。注册表值Kmode包含了Windows子系统的内核模式部分的文件名称,Win32k.sys。
Windows子系统。尽管Windows在设计时,要求支持多个独立的环境子系统,但是从实践的角度来看,让每个子系统都实现所有的代码来处理窗口和显示I/O,显然会导致大量重复的系统函数。因为Windows是基础的子系统,所以Windows的设计者决定将这些基本的功能放在Windows子系统中,让其他子系统调用来完成显示I/O。Windows子系统由以下主要组件构成。
对于每个会话,环境子系统进程(Csrss.exe)有一个实例加载三个DLL(Basesrv.dll、Winsrv.dll和Csrsrv.dll),它们包含下列支持:创建或删除进程和线程;对16位DOS虚拟机(VDM)进程的部分支持(仅32位Windows);SxS(Side-by-Side)/Fusion和清单文件(Manifest)支持;其他一些函数,比如GetTempFile、DefineDOSDevice、ExitWindowsEx,以及几个自然语言支持函数。
内核模式设备驱动程序(Win32k.sys)包含下列支持:窗口管理器,控制窗口显示,管理屏幕输出,采集来自键盘、鼠标和其他设备的输入,同时负责将用户消息传递给应用程序;图形设备接口,它是专门针对图形输出设备的函数库,其中包括线段、文本和图形的绘制函数,以及图形控制函数;DirectX功能的包装函数,Windows对DirectX的支持是在另一个内核驱动程序(Dxgkrnl.sys)中实现的。
控制台宿主进程(Conhost.exe),提供了对控制台(字符环境)应用程序的支持。
子系统DLL(比如Kernel32.dll、Advapi32.dll、User32.dll和Gdi32.dll),将已经文档化的Windows API函数,转译成Ntoskrnl.exe和Win32k.sys中恰当的且绝大多数未文档化的内核模式系统服务调用。
图形设备驱动程序,与硬件相关的图形显示器驱动程序、打印机驱动程序和视频微端口驱动程序。
因为子系统的大部分运行在内核模式下,所以,只有少数一些Windows函数要向Windows子系统进程发送消息:进程和线程的创建和终止、网络驱动器号以及临时文件的创建。