日期:2014-05-17  浏览次数:20787 次

Windows系统程序员的“内功”修炼

Windows系统程序员的“内功”修炼
2010年12月08日
  注:这篇blog是从一本书(《竹林蹊径--深入浅出Windows驱动开发》)的推荐序中摘录出来的。
  我一直认为,编写程序是一件很奇妙的事情,它可以带来创造和控制的欲望。每当我阅读或者编写一段代码时,脑子里自然地就会想象这段代码怎样完成预定的逻辑。当面对一个不熟悉的开发环境,或者一个新的基础平台时,首先要清楚这个环境或者平台是如何工作的,以及提供了哪些功能。代码本身可能非常复杂,甚至奥妙无穷,但通常情况下,真正优美的高质量代码往往是简单的、易于理解的。对于代码编写者或者维护者来说,真正见功夫的地方不在于代码本身,而在于对下层开发平台的理解和驾驭能力,可能这就是俗称的"内功"。
  这个观点既适用于应用软件程序员,也适用于系统软件程序员。对于应用软件程序员,低层的应用开发平台是支撑应用开发的基础,譬如,基于Windows SDK来开发Windows应用程序,那么,程序员有必要理解Windows SDK中的基本要素,诸如消息分发机制、各种图形功能等。在这种情况下,阅读一些典型的例子程序代码往往能起到快速引领入门的效果。同样地,C/C++程序员如果局限于C/C++语言本身,很难编写出高质量的实用程序。他们不仅要掌握C/C++运行库中函数和类型的用法,甚至还要理解这些函数和类型的实现机理。即使源代码层面上的库,例如STL(C++的标准模板库),也需要理解其代码实现才能灵活自如地用好这些库(比如STL中的各种容器数据结构、迭代器或算法)。
  那么,对于系统软件程序员,"内功"是什么呢?系统软件是指操作系统本身或者依附于操作系统上为应用软件提供服务的软件。系统软件可能有机会跟硬件直接打交道,这赋予了程序员更强的控制能力,他们有机会介入操作系统的行为逻辑,甚至改变操作系统的行为特性。但随之而来的是对系统软件代码的更高要求。现代操作系统为应用软件提供了很强的容错能力,应用程序的失败通常不会波及到操作系统自身的稳定性,但操作系统对系统软件的容错能力却比较有限,毕竟系统软件运行起来之后可能被融入到操作系统的执行逻辑中成为操作系统的一部分。因此,理解和掌握操作系统的运行机制成为系统程序员编写出正确、高效的系统软件的基本前提。所谓"内功",便着落在此。
  在Windows平台上开发软件,编写Windows内核驱动程序是最为考验程序员"内功"的。内核驱动程序的代码量通常不大,但驱动程序框架中的任何一个函数,甚至这些函数中任何一行代码都可能背后蕴含着复杂的逻辑,或者隐式的要求和假设。即使驱动程序编写者在纯粹自行定义的函数中,也必须谨慎地关注一些与环境有关的因素,譬如代码是否可被中断、是否可重入,或者所引用的内存是否被交换到外存。另一方面,应用软件开发中的很多概念,比如地址空间、内存管理、异常处理和多线程并发等等,在驱动程序开发中可能需要有不同的理解方法。此外,常用的C运行库函数基本上不再适合于驱动程序了,驱动程序编写者必须面对一个全新的底层环境和支持平台。因此,要编写可正确运行的驱动程序,程序员不仅要清楚地理解驱动程序所针对的目标设备或功能(可能包括硬件设备的各种特性),还要掌握Windows内核是如何与驱动程序打交道的,以及内核中诸多管理和运行机制,尤其是内存管理、线程调度和并发控制。
  当Windows内核驱动程序被加载到内核中并且启动以后,它们变成了Windows内核的一部分,驱动程序中的接口函数在恰当的时刻被内核调用,这是Windows驱动程序的基本工作方式。Microsoft定义了WDM(Windows驱动程序模型)来规定驱动程序的结构以及Windows内核如何与WDM驱动程序打交道。WDM不仅包括I/O管理器定义的驱动程序框架,还定义了在驱动程序中如何支持PnP(Plug and Play,即插即用)、电源管理和WMI(Windows Management Instrumentation,Windows管理规范)。因此,若要编写一个完全支持WDM的驱动程序,也需要理解WDM中所涉及的各个内核组件。
  为了便于Windows驱动程序的开发,Microsoft定义了一个驱动程序框架,称为WDF(Windows Driver Foundation),其中针对内核驱动程序的部分称为KMDF(Kernel-Mode Driver Framework)。KMDF实际上是一个库,它封装了WDM中一些基本的代码逻辑,从而使程序员可以更加方便地编写出WDM驱动程序。KMDF可以部分地简化Windows内核驱动程序的开发任务,但是本质上它并没有降低内核驱动程序的复杂性,甚至需要程序员付出额外的学习努力。
  总而言之,作为一名系统程序员,你需要洞悉目标操作系统中与你的软件打交道的各个部件,也要非常清楚地知道你所依赖的开发工具是如何帮助你做到这一点的。系统程序员往往面临着比应用程序员更长的学习曲线,但是,系统程序员从编写程序中获得的乐趣也是在应用层上难以体会得到的。