分类: LINUX
2014-03-14 13:43:27
原文地址:Linux内核探索之路——关于书 作者:lli_njupt
在学习Linux内核代码的过程中,定会参考很多书籍以及网路资源,但是并不是所有的书籍和资源都能够帮助你前进,或者说是能够将你引导向正确而高效的道路。
在学习的一些阶段可能会需要不同的书,比如在第一个阶段,一些基本的书籍都是可以参考的。这个阶段的书籍非常多,比如《鸟哥的linux私房菜》,它介绍了Linux系统的基本概念和使用。《高级Bash脚本编程指南》可以说是学习Shell的利器,翔实的示例和解释足以让你成为Shell专家。另外可以在Linux平台架设一些常用的服务器等以增加实践。
由于大部分人在大学期间都学习过C语言,所以在学习的第二阶段依然可以把那本经典的谭浩强读本放在手边作为参考手册。《Linux C编程一站式学习》这本书在介绍标准C的同时则倾向于Linux平台的编程:网络编程,ELF格式解析,链接的原理和Makefile。此时如果不提大名鼎鼎的《UNIX环境高级编程》和《UNIX网络编程》这两本书,一定会遭到抗议。尽管书名包含UNIX,但是由于Linux是类UNIX的系统,所以这两本书同样适用于Linux环境。
《UNIX环境高级编程》被誉为UNIX编程“圣经”,并且一版再版。它的首席作者W.Richard Stevens是国际知名的UNIX和网络专家;受人尊敬的计算机图书作家;同时他还是广受欢迎的教师和顾问。Stevens先生不幸逝于1999年9月1日。UNIX操作系统的原作者Dennis Ritchie对该书的评价是“公认的优秀、匠心独具的名著”。再多的赞誉都不为过,因为除了参考系统函数或者glibc库函数的文档或者直接查看源码能够获取比该书更全面的信息外,似乎别无他法。如果你能够在某些网站或者书籍获取到比该书更详尽的描述和分析,那么把它作为参考一定不会错。非常喜欢这本书首页上的“Standing on Shoulders of Giants”——站在巨人的肩上。
《UNIX网络编程》同为W.Richard Stevens的另一部名著,它弥补了《UNIX环境高级编程》在网络编程方面叙述的不足,与该书享有同样的地位。该书的最新版本由世界著名网络专家再次修订,添加了IPv6,SCTP以及密匙管理相关的内容。所以值得庆幸:这两本书都没有因为Stevens先生的离去而失去时代的活力。
杰出人物的成就总是在让人景仰的同时,令人不由自主的惊叹。《TCP/IP 详解》(三卷本)作为了解当前盛行世界的因特网原理的圣经级著作,也同样出自其手。“Richard Stevens以他的写作风格和作品,在TCP/IP编程领域竖立起一座丰碑,令其他作者高山仰止,心向往之”。
在这里一气儿介绍了Stevens先生的这三本书,应该没有人会非议。如果你在一些Linux编程或着网络方面的资深著作中的参考书目中没有找到这三本书的名字,那确实有点不可思议。
在参考以上书籍,并在个人努力和工作经验积累的情况下,到达第三个阶段是水到渠成的事。这似乎是一个关键的时刻:要么继续留在原地,要么进入一个完全不同的领域。关于探索Linux内核代码的书籍这些年来已经相当繁多。如果粗略的对它们进行分类,大概如下:
一些书籍可能会大量的引用代码,但是不对该功能模块的原理和细节进行详述,最多在源码中给出一些翻译后的注释。这类书籍适合做参考,却不适合用它来系统的学习内核原理。否则很快就将进入“一鼓作气,再而衰”的境地,因为越来越多的疑问将耗尽你的激情,最后除了头脑混乱外,很可能得出学习内核太难的结论。这里对这类书做了一定的批判,但是它们依然不乏作为参考资料的价值。在最近一段时间的相关出版物中,这类书籍已经越来越少,而一批质量较高的国内书籍开始呈现出来。
有些书籍单独针对内核特定的区域或者说子系统来讲解,比如内核驱动,网络实现等。这类书籍针对性较强,对细节比较注重,能够对一些问题分析的较为透彻,另外一个优点就是这类书往往比较薄,让人容易接受。当然了这也就意味着它不能给你在另一个内核功能领域以有效的指导。这类书的典型代表有:《深入理解LINUX网络内幕》,《深入理解Linux虚拟内存管理》,《Linux设备驱动程序》和《Embedded Linux Primer》。更确切的说后两本并不是讲解内核原理的,它们针对的是内核的应用,所以在选择时应该加以区分,但是《Essential Linux Device Drivers》这本书有取代《Linux设备驱动程序》之势,它补充了驱动相关的内核原理部分。
还有一类书,这类书不太好对它进行分类,它们对深入理解底层硬件相关部分的基本原理帮助颇大,但毕竟描述的内核版本和当前的2.6内核版本相去甚远,比如对0.1版本的分析,如果单从这些资源来学习当前的内核版本似乎有点“舍近求远”。它们的真正价值在于分析内核的角度,也即它们没有随波逐流的去跟随已有的著作,而是独辟蹊径,从另外一个侧面揭示Linux的远古面纱。这种书籍的代表有《Linux内核完全剖析》和《Linux内核设计的艺术》,从后者的内容可以看出它应该能代表当前国内在Linux领域的部分研究水平。
好了,如果在这一领域没有一些重量级的选手出场一定说不过去。《深入理解Linux内核》和《Linux内核设计与实现》,这两本书分别被简写为ULK和LKD,它们应该算是一个重量级的。并且论述的方式非常像操作系统原理,但是是结合Linux的系统原理。把它们作为教材是非常之好。ULK可以说就是Linux版的系统原理,从行文风格,知识点的切入方式基本是属于学术派:首先是提纲挈领的简介,然后是细分的要点详述,进而引述少量的代码。LKD与ULK非常相似,但是很明显的感觉到它对代码的引用要多,实践性更强,比如它会谈到内核的代码结构,编译,调试,glibc库以及Linux的代码风格等,属于实践派,但又不完全,因为它比实践的书籍多了理论的介绍,但是代码引用的程度又太少,如果完全跟随它来通过开发板实践相关的功能子系统,可以说能够摸着石头过河的时候非常少,大部分的关键代码都无法从书中找到蛛丝马迹。另外由于它页数的限制,很多内核功能的细节都被忽略掉了,虽然第三版的英文版已经发行,除了最后一个章节的内容有大的改变外,基本延续了前版叙述的知识范围。所以它渐渐有被后来者《深入Linux内核架构》LKA代替的危险。
书籍名称 |
作者 |
出版时间 |
内核版本 |
Understanding the Linux Kernel, 3rd Edition(ULK) |
Daniel P. Bovet, Marco Cesati |
November 2005 |
2.6.11 |
Linux Kernel Development, 3rd Edition(LKD) |
Robert Love |
June 2010 |
2.6.34 |
Professional Linux Kernel Architecture(LKA) |
Wolfgang Mauerer
|
January 2008 |
2.6.24 |
Linux内核经典书籍
ULK基本是属于学术派的著作,两位作者都是学府内的教授,他们自然在有意无意中会更专注操作系统的原理和算法,而或多或少限制对代码实现的论述。所以它属于通用操作系统原理著作但又向Linux实现靠近的理论论述的一种过渡,由于ULK将所有篇幅放在了Linux对操作系统的实现上,所以它在理论层面的论述可以说鲜有挑战者。总体来看ULK和LKD之间的关系,很容易发现LDK的出现是用来弥补ULK在论述实践这一块的缺失,但是不知为什么LKD对实践的论述又不彻底,反而造成了一种有点儿尴尬的骑墙势。
不妨做如下的推理假设:如果在多年前,那时候内核代码的维护还基本在一个有限的圈子里,这些人都是计算机黑客或者是内核代码的狂热爱好者,他们完全有能力维护好各自负责的代码部分。但是随着功能的增加,代码量也与日俱增,而代码量的增加会以非线性的方式影响代码的复杂度,这导致对代码的把握非常不易,维护起来的难度可想而知。直至今日,内核代码的维护人员有点青黄不接。所以合理的猜测是:LKD最初出现时是为了给内核开发的新手做一个入门式的引导,因此它花了几章的篇幅在介绍Linux代码结构,编译,调试以及代码风格上。
LKA是由德国Wolfgang Mauerer完成的。所以它的原版是德文版,而英文版的出现已经到了2008年。这本书在国内推出的时间则推迟到了2010年的后半年。尽管笔者只看了这本书的若干章,但可以毫不扩张的说,它是在Linux实践领域进行相对全面的论述的集大成者。看一本书对知识点的把握深度和细度,只要看它对Linux内核中最复杂的内存管理机制的论述就可以了,比如它对内存区类型ZONE_MOVABLE的作用的叙述,在大多数的类似书籍中都难以找到对它的详细描述。另外一点值得肯定的是,它在内核代码的应用中有非常好的连贯性,使用开发板跟随它的论述进行实践验证是可行的,摸着石头过河是现实的了。由于深度细度以及代码连惯性两方面的要求,尽管这本书只有十九章,中文版的页数已经达到了一千多页。总结:这本书是用来研究内核的,它并不太注重对内核的使用,而大多数人可能是为了学习内核驱动的开发,这个LDD3或者ELDD就可以了,使用LKA反而是南辕北辙。但是如果你想洞悉Linux对操作系统的实现,那么选择它基本上没错了。
尽管LKA比LDA具有很大的优势,它也不是完美无瑕,一些地方可能翻译得不够准确,比如内存管理中对页和页帧的使用,有些混乱。另外一些句子可能翻译的不够恰当,比如P23页的“对于后者来说有大量的调试器可用,而对于后者来说”改为“而相对于后者来说”更为贴切。另外原版作者可能主要在x86上进行实验和研究,所以有些地方可能适用于x86架构,但并不适合所有的平台。例如P111中的“node_start_pfn在UMA系统中总是0”,诚然x86的CPU对物理RAM的地址从0开始分配,但是ARM的CPU就不尽然,它通常都不是从0开始。P137中“减去0Xc0000000,则可以获得对应的物理地址”,但在ARM上应该还要加上一个物理地址的偏移。尽管如此,瑕不掩瑜。
未知何朝何代,武林中出现了名震天下的两大流派:剑宗和气宗。它们吸取了中原各大门派武术之精华,适时有两少年各入两宗,相约十载一战。
两人各拜其师,砥砺寒暑,未敢懈怠。光阴荏苒,白驹过隙;十载春秋,弹指一挥。是日,会稽山下,只见一人仙风荡漾,一人剑气浩然。日出而战,披星而息。剑出。
廿十载,气完胜。又十载,日出而战,而三日不能息!何也?气中有见,剑中有气,阴阳相合者也。
在经过了一番“讨价还价”之后,似乎找到了学习内核原理的最佳组合了:理论与实现,ULK和LKA,似乎把它们缩写成ULKA更好,如此则阴阳相合,关于书也就说到这了!
最后的啰嗦:如何看书?是一气看完?还是分章节,一一攻破呢?显然是一一攻破要好的多,所有章节看下来的周期太长,难于把握。实际上还要根据难易程度来决定,有些章节需要非常细心的研读。另外要注意实践和理论一定要结合,比较简单的功能实现,可以先实践,也即先循着LKA讲的顺序看看代码,然后自我分析,接着结合ULK的理论,从全局把握;比较复杂的功能模块,则可以先看ULK理解基本的系统原理,然后再结合LKA进行实践。本质上需要把90%的时间花在这两本书和在开发板的实践上,只有通过它们还不能完全理解的情况下,再去参考其他的书籍和资源,这可以保证学习的效率。