Linux操作系统源代码详细分析(二)(转)[@more@]
第2章 代 码 初 识
本章首先从较高层次介绍Linux内核源程序的概况,这些都是大家关心的一些基本特点。随后将简要介绍一些实际代码。最后介绍如何编译内核。
2.1 Linux内核源程序的部分特点
在过去的一段时期,Linux内核同时使用C语言和汇编语言来实现。这两种语言需要一定的平衡:C语言编写的代码移植性较好、易于维护,而汇编语言编写的程序则速度较快。一般只有在速度是关键因素或者一些因平台相关特性而产生的特殊要求(例如直接和内存管理硬件进行通讯)时才使用汇编语言。
正如实际中所做的,即使内核并未使用C++的对象特性,部分内核也可以在g++(GNU的C++编译器)下进行编译。同其他面向对象的编程语言相比较,相对而言C++的开销是较低的,但是对于内核开发人员来说,这已经是太多了。
内核开发人员不断发展编程风格,形成了Linux代码独有的特色。本节将讨论其中的一些问题。
2.1.1 gcc特性的使用
Linux内核被设计为必须使用GNU的C编译器gcc来编译,而不是任何一种C编译器都可以使用。内核代码有时要使用gcc特性,本书将陆续介绍其中的一部分。
一些gcc特有代码只是简单地使用gcc语言扩展,例如允许在C(不只是C++)中使用inline关键字指示内联函数。也就是说,代码中被调用的函数在每次函数调用时都会被扩充,因而就可以节约实际函数调用的开销。
一般情况下,代码的编写方式比较复杂。因为对于某些类型的输入,gcc能够产生比其他输入效率更高的执行代码。从理论上讲,编译器可以优化具有相同功能的两种对等的方法,并且得到相同的结果。因此,代码的编写方式是无关紧要的。但在实际上,用某种方法编写所产生的代码要比用另外一些方法编写所产生的代码执行速度快许多。内核开发人员知道怎样才能产生更高效的执行代码,这不断地在他们编写的代码中反映出来。
例如,考虑内核中经常使用的goto语句—为了提高速度,内核中经常大量使用这种一般要避免使用的语句。在本书中所包含的不到40 000行代码中,一共有500多条goto语句,大约是每80行一个。除汇编文件外,精确的统计数字是接近每72行一个goto语句。公平地说,这是选择偏向的结果:比例如此高的原因之一是本书中涉及的是内核源程序的核心,在这里速度比其他因素都需要优先考虑。整个内核的比例大概是每260行一个goto语句。然而,这仍然是我不再使用Basic进行编程以来见过的使用goto频率最高的地方。
代码必需受特定编译器限制的特性不仅与普通应用程序的开发有很大不同,而且也不同于大多数内核的开发。大多数的开发人员使用C语言编写代码来保持较高的可移植性,即使在编写操作系统时也是如此。这样做的优点是显而易见的,最为重要的一点是一旦出现更好的编译器,程序员们可以随时进行更换。
内核对于gcc特性的完全依赖使得内核向新的编译器上移植更加困难。最近Linus对这一问题在有关内核的邮件列表上表明了自己的观点:“记住,编译器只是一个工具。”这是对依赖于gcc特性的一个很好的基本思想的表述:编译器只是为了完成工作。如果通过遵守标准还不能达到工作要求,那么就不是工作要求有问题,而是对于标准的依赖有问题。
在大多数情况下,这种观点是不能被人所接受的。通常情况下,为了保证和程序语言标准的一致,开发人员可能需要牺牲某些特性、速度或者其他相关因素。其他的选择可能会为后期开发造成很大的麻烦。
但是,在这种特定的情况下,Linus是正确的。Linux内核是一个特例,因为其执行速度要比向其他编译器的可移植性远为重要。如果设计目标是编写一个可移植性好而不要求快速运行的内核,或者是编写一个任何人都可以使用自己喜欢的编译器进行编译的内核,那么结论就可能会有所不同了;而这些恰好不是Linux的设计目标。实际上,gcc几乎可以为所有能够运行Linux的CPU生成代码,因此,对于gcc的依赖并不是可移植性的严重障碍。
在第3章中我们将对内核设计目标进行详细说明。
本章首先从较高层次介绍Linux内核源程序的概况,这些都是大家关心的一些基本特点。随后将简要介绍一些实际代码。最后介绍如何编译内核。
2.1 Linux内核源程序的部分特点
在过去的一段时期,Linux内核同时使用C语言和汇编语言来实现。这两种语言需要一定的平衡:C语言编写的代码移植性较好、易于维护,而汇编语言编写的程序则速度较快。一般只有在速度是关键因素或者一些因平台相关特性而产生的特殊要求(例如直接和内存管理硬件进行通讯)时才使用汇编语言。
正如实际中所做的,即使内核并未使用C++的对象特性,部分内核也可以在g++(GNU的C++编译器)下进行编译。同其他面向对象的编程语言相比较,相对而言C++的开销是较低的,但是对于内核开发人员来说,这已经是太多了。
内核开发人员不断发展编程风格,形成了Linux代码独有的特色。本节将讨论其中的一些问题。
2.1.1 gcc特性的使用
Linux内核被设计为必须使用GNU的C编译器gcc来编译,而不是任何一种C编译器都可以使用。内核代码有时要使用gcc特性,本书将陆续介绍其中的一部分。
一些gcc特有代码只是简单地使用gcc语言扩展,例如允许在C(不只是C++)中使用inline关键字指示内联函数。也就是说,代码中被调用的函数在每次函数调用时都会被扩充,因而就可以节约实际函数调用的开销。
一般情况下,代码的编写方式比较复杂。因为对于某些类型的输入,gcc能够产生比其他输入效率更高的执行代码。从理论上讲,编译器可以优化具有相同功能的两种对等的方法,并且得到相同的结果。因此,代码的编写方式是无关紧要的。但在实际上,用某种方法编写所产生的代码要比用另外一些方法编写所产生的代码执行速度快许多。内核开发人员知道怎样才能产生更高效的执行代码,这不断地在他们编写的代码中反映出来。
例如,考虑内核中经常使用的goto语句—为了提高速度,内核中经常大量使用这种一般要避免使用的语句。在本书中所包含的不到40 000行代码中,一共有500多条goto语句,大约是每80行一个。除汇编文件外,精确的统计数字是接近每72行一个goto语句。公平地说,这是选择偏向的结果:比例如此高的原因之一是本书中涉及的是内核源程序的核心,在这里速度比其他因素都需要优先考虑。整个内核的比例大概是每260行一个goto语句。然而,这仍然是我不再使用Basic进行编程以来见过的使用goto频率最高的地方。
代码必需受特定编译器限制的特性不仅与普通应用程序的开发有很大不同,而且也不同于大多数内核的开发。大多数的开发人员使用C语言编写代码来保持较高的可移植性,即使在编写操作系统时也是如此。这样做的优点是显而易见的,最为重要的一点是一旦出现更好的编译器,程序员们可以随时进行更换。
内核对于gcc特性的完全依赖使得内核向新的编译器上移植更加困难。最近Linus对这一问题在有关内核的邮件列表上表明了自己的观点:“记住,编译器只是一个工具。”这是对依赖于gcc特性的一个很好的基本思想的表述:编译器只是为了完成工作。如果通过遵守标准还不能达到工作要求,那么就不是工作要求有问题,而是对于标准的依赖有问题。
在大多数情况下,这种观点是不能被人所接受的。通常情况下,为了保证和程序语言标准的一致,开发人员可能需要牺牲某些特性、速度或者其他相关因素。其他的选择可能会为后期开发造成很大的麻烦。
但是,在这种特定的情况下,Linus是正确的。Linux内核是一个特例,因为其执行速度要比向其他编译器的可移植性远为重要。如果设计目标是编写一个可移植性好而不要求快速运行的内核,或者是编写一个任何人都可以使用自己喜欢的编译器进行编译的内核,那么结论就可能会有所不同了;而这些恰好不是Linux的设计目标。实际上,gcc几乎可以为所有能够运行Linux的CPU生成代码,因此,对于gcc的依赖并不是可移植性的严重障碍。
在第3章中我们将对内核设计目标进行详细说明。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10617542/viewspace-963073/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/10617542/viewspace-963073/