开篇html
学习内核,每一个人都有本身的学习方法,仁者见仁智者见智。如下是我在学习过程当中总结出来的东西,对自身来讲,我认为比较有效率,拿出来跟你们交流一下。linux
内核学习,一偏之见;疏漏不免,恳请指正。程序员
为何写这篇博客编程
刚开始学内核的时候,不要执着于一个方面,不要专一于一个子系统就一头扎到实际的代码行中去,由于这样的话,牵涉的面会很广,会碰到不少困难,容易产生挫败感,一个函数体中(假设刚开始的时候正在学习某个方面的某个具体的功能函数)极可能掺杂着其余各个子系统方面设计理念(可能是大量相关的数据结构或者全局变量,用于支撑该子系统的管理工做)下相应的代码实现,这个时候看到这些东西,纷繁芜杂,是没有头绪并且很不理解的,会产生不少不少的疑问,(这个时候若是对这些疑问纠缠不清,刨根问底,那么事实上就是在学习当前子系统的过程当中频繁的去涉足其余子系统,这时候注意力就分散了),而事实上等了解了各个子系统后再回头看这些东西的话,就简单多了,并且思路也会比较清晰。因此,要避免 “只见树木,不见森林”,不要急于深刻到底层代码中去,不要过早研究底层代码。安全
我在大二的时候刚开始接触内核,就犯了这个错误,一头扎到内存管理里头,去看很是底层的实现代码,虽然也是创建在内存管理的设计思想的基础上,可是相对来讲,比较孤立,由于此时并无学习其它子系统,应该说不管是视野仍是思想,都比较狭隘,因此代码中牵涉到的其它子系统的实现我都直接跳过了,这一点还算聪明,固然也是无可奈何的。网络
个人学习方法数据结构
刚开始,我认为主要的问题在于你知道不知道,而不是理解不理解,某个子系统的实现采用了某种策略、方法,而你在学习中须要作的就是知道有这么一回事儿,而后才是理解所描述的策略或者方法。多线程
根据本身的学习经验,刚开始学习内核的时候,我认为要作的是在本身的脑海中创建起内核的大致框架,理解各个子系统的设计理念和构建思想,这些理念和思想会从宏观上呈献给你清晰的脉络,就像一个去除了枝枝叶叶的大树的主干,一目了然;固然,确定还会涉及到具体的实现方法、函数,可是此时接触到的函数或者方法位于内核实现的较高的层次,是主(要)函数,已经了解到这些函数,针对的是哪些设计思想,实现了什么样的功能,达成了什么样的目的,混个脸熟的说法在这儿也是成立的。至于该主函数所调用的其它的辅助性函数就等同于枝枝叶叶了,没必要太早就去深究。此时,也就初步创建起了内核子系统框架和代码实现之间的关联,关联其实很简单,好比一看到某个函数名字,就想起这个函数是针对哪一个子系统的,实现了什么功能。架构
我认为此时要看的就是LKD3,这本书算是泛泛而谈,主要就是从概念,设计,大的实现方法上描述各个子系统,而对于具体的相关的函数实现的代码讲解不多涉及(对比于ULK3,此书主要就是关于具体函数代码的具体实现的深刻分析,固然,你也能够看,可是过早看这本书,会感受很痛苦,很枯燥无味,基本上都是函数的实现),不多,但不是没有,这就很好,知足咱们当前的需求,还避免咱们过早深刻到实际的代码中去。并且本书在一些重要的点上还给出了写程序时的注意事项,算是指导性建议。主要的子系统包括:内存管理,进程管理和调度,系统调用,中断和异常,内核同步,时间和定时器管理,虚拟文件系统,块I/O层,设备和模块。(这里的前后顺序其实就是LKD3的目录的顺序)。并发
我学习的时候是三本书交叉着看的,先看LKD3,专于一个子系统,主要就是了解设计的原理和思想,固然也会碰到对一些主要函数的介绍,但大多就是该函数基于前面介绍的思想和原理完成了什么样的功能,该书并无就函数自己的实现进行深刻剖析。而后再看ULK3和PLKA上看一样的子系统,可是并不仔细分析底层具体函数的代码,只是粗略地、不求甚解地看,甚至不看。由于,有些时候,在其中一本书的某个点上,卡壳了,不是很理解了,在另外的书上你可能就碰到对同一个问题的不一样角度的描述,说不许哪句话就能让你豁然开朗,如醍醐灌顶。我常常碰到这种状况。
并非说学习过程当中对一些函数体的实现彻底就忽略掉,只要本身想完全了解其代码实现,没有谁会阻止你。我是在反复阅读过程当中慢慢深刻的。好比VFS中文件打开须要对路径进行分析,须要考虑的细节很多(.././之类的),可是其代码实现是很好理解的。再好比,CFS调度中根据shedule latency、队列中进程个数及其nice值(使用的是动态优先级)计算出分配给进程的时间片,没理由不看的,这个过重要了,并且也颇有意思。
ULK3也会有设计原理与思想之类的归纳性介绍,基本上都位于某个主题的开篇段落。可是更多的是对支持该原理和思想的主要函数实现的具体分析,一样在首段,一句话综述函数的功能,而后对函数的实现以一、二、3,或者a、b、c步骤的形式进行讲解。我只是有选择性的看,有时候对照着用source insight打开的源码,确认一下代码大致上确实是按书中所描述的步骤实现的,就当是增长感性认识。因为步骤中掺杂着各类针对不一样实现目的安全性、有效性检查,若是不理解就先跳过。这并不妨碍你对函数体功能实现的总体把握。
PLKA介于LKD3和ULK3之间。我以为PLKA的做者(看照片,真一德国帅小伙,技术如此了得)确定看过ULK,不管他的本意仍是有意,总之PLKA仍是跟ULK有所不一样,对函数的仔细讲解都作补充说明,去掉函数体中边边角角的状况,好比一些特殊状况的处理,有效性检查等,而不妨碍对整个函数体功能的理解,这些他都有所交代,作了声明;并且,就像LKD3同样,在某些点上也给出了指导性编程建议。做者们甚至对同一个主要函数的讲解的着重点都不同。这样的话,对咱们学习的人而言,有助于加深理解。另外,我认为很重要的一点就是PLKA针对的2.6.24的内核版本,而ULK是2.6.11,LKD3是2.6.34。在某些方面PLKA比较接近现代的实现。其实做者们之因此分别选择11或者24,都是由于在版本发行树中,这两个版本在某些方面都作了不小的变更,或者说是具备标志性的转折点(这些信息大可能是在书中的引言部分介绍的,具体的细节我想不起来了)。
Intel V3,针对X86的CPU,本书天然是系统编程的权威。内核部分实现均可以在本书找到其根源。因此,在读以上三本书某个子系统的时候,不要忘记能够在V3中相应章节找到一些基础性支撑信息。
在读书过程当中,会产生至关多的疑问,这一点是确信无疑的。 大到搞不明白一个设计思想,小到不理解某行代码的用途。各个方面,各类疑问,你彻底能够把不理解的地方都记录下来(不过,我并无这么作,没有把疑问所有记下来,只标记了不多一部分我认为很关键的几个问题),专门写到一张纸上,不对,一个本上,我确信会产生这么多的疑问,否则内核相关的论坛早就能够关闭了。其实,大部分的问题(其中不少问题都是你知道不知道有这么一回事的问题)均可以迎刃而解,只要你肯回头再看,书读百遍,其义自现。多看几遍,前先后后的联系明白个七七八八是没有问题的。我也这么作了,针对某些子系统也看了好几遍,切身体会。
当你按顺序学习这些子系统的时候,前面的章节极可能会引用后面的章节,就像PLKA的做者说的那样,彻底没有向后引用是不可能的,他能作的只是尽可能减小这种引用而又不损害你对当前问题的理解。不理解,不要紧,跳过就好了。后面的章节一样会有向前章节的引用,不过这个问题就简单一些了 ,你能够再回头去看相应的介绍,当时你不太理解的东西,极可能这个时候就知道了它的设计的目的以及具体的应用。不求甚解只是暂时的。好比说,内核各个子系统之间的交互和引用在代码中的体现就是实现函数穿插调用,好比你在内存管理章节学习了的内存分配和释放的函数,而你是了解内存在先的,在学习驱动或者模块的时候就会碰到这些函数的调用,这样也就比较容易接受,不至于太过茫然;再好比,你了解了系统时间和定时器的管理,再回头看中断和异常中bottom half的调度实现,你对它的理解就会加深一层。
子系统进行管理工做须要大量的数据结构。子系统之间交互的一种方式就是各个子系统各自的主要数据结构经过指针成员相互引用。学习过程当中,参考书上在讲解某个子系统的时候会对数据结构中主要成员的用途解释一下,但确定不会覆盖所有(成员比较多的状况,例如task_struct),对其它子系统基于某个功能实现的引用可能解释了,也可能没作解释,还可能说这个变量在何处会作进一步说明。因此,不要纠结于一个不理解的点上,暂且放过,回头还能够看的。之间的联系能够在对各个子系统都有所了解以后再创建起来。其实,我仍然在强调先理解概念和框架的重要性。
等咱们完成了创建框架这一步,就能够选择一个比较感兴趣的子系统,好比驱动、网络,或者文件系统之类的。这个时候你再去深刻了解底层代码实现,相较于一开始就钻研代码,更容易一些,并且碰到了不解之处,或者忘记了某个方面的实现,此时你彻底能够找到相应的子系统,由于你知道在哪去找,查漏补缺,不只完成了对当前函数的钻研,并且能够回顾、温习之前的内容,融会贯通的时机就在这里了。
《深刻理解linux虚拟内存》(2.4内核版本),LDD3,《深刻理解linux网络技术内幕》,几乎每个子系统都须要一本书的容量去讲解,因此说,刚开始学习不宜对某个模块太过深刻,等对各个子系统都有所了解了,再有针对性的去学习一个特定的子系统。这时候对其它系统的援引均可以让咱们再也不感到茫然、复杂,不知所云。
好比,LDD3中的如下所列章节:构造和运行模块,并发和竞态,时间、延迟及延缓操做,分配内存,中断处理等,都属于驱动开发的支撑性子系统,虽然说本书对这些子系统都专门开辟一个章节进行讲解,可是详细程度怎么能比得上PLKA,ULK3,LKD3这三本书,看完这三本书,你会发现读LDD3这些章节的时候简直跟喝白开水同样,太随意了,由于LDD3的讲解比之LKD3更粗略。打好了基础,PCI、USB、TTY驱动,块设备驱动,网卡驱动,须要了解和学习的东西就比较有针对性了。这些子系统就属于通用子系统,了解以后,基于这些子系统的子系统的开发—驱动(需进一步针对硬件特性)和网络(需进一步理解各类协议)—相对而言,其学习难度大大下降,学习进度大大加快,学习效率大大提高。说着容易作来难。达到这样一种效果的前提就是:必须得静下心来,认真读书,要看得进去,PLKA,ULK3厚得都跟砖头块儿同样,使人望之生畏,若是没有兴趣,没有热情,没有毅力,不管如何都是不行,由于须要时间,须要很长时间。我并非说必须打好了基础才能够进行驱动开发,只是说打好了基础的状况下进行开发会更轻松,更有效率,并且本身对内核代码的驾驭能力会更强大。这只是我我的看法,我本身的学习方式,仅供参考。
语言
PLKA是个德国人用德语写的,后来翻译成英文,又从英文翻译成中文,我在网上书店里没有找到它的纸质英文版,因此就买了中文版的。ULK3和LKD3都是英文版的。大牛们写的书,遣词造句真的是简洁,易懂,看原版对咱们学习计算机编程的程序员来讲彻底不成问题,最好原汁原味。若是一本书确实翻译地很好,咱们固然能够看中文版的,用母语进行学习,理解速度和学习进度固然是很快的,不做他想。看英文的时候不要脑子里想着把他翻译成中文,不必。
API感想
“比起知道你所用技术的重要性,成为某一个特别领域的专家是不重要的。知道某一个具体API调用一点好处都没有,当你须要他的时候只要查询下就行了。”这句话源于我看到的一篇翻译过来的博客。我想强调的就是,这句话针应用型编程再合适不过,可是内核API就不彻底如此。
内核至关复杂,学习起来很不容易,可是当你学习到必定程度,你会发现,若是本身打算写内核代码,到最后要关注的仍然是API接口,只不过这些API绝大部分是跨平台的,知足可移植性。内核***基本上已经标准化、文档化了这些接口,你所要作的只是调用而已。固然,在使用的时候,最好对可移植性这一话题在内核中的编码约定烂熟于心,这样才会写出可移植性的代码。就像应用程序同样,可使用开发商提供的动态库API,或者使用开源API。一样是调用API,不一样点在于使用内核API要比使用应用API了解的东西要多出许多。
当你了解了操做系统的实现—这些实现可都是对应用程序的基础性支撑啊—你再去写应用程序的时候,应用程序中用到的多线程,定时器,同步锁机制等等等等,使用共享库API的时候,联系到操做系统,从而把对该API的文档描述同本身所了解到的这些方面在内核中的相应支撑性实现结合起来进行考虑,这会指导你选择使用哪个API接口,选出效率最高的实现方式。对系统编程很有了解的话,对应用编程不无益处,甚至能够说是大有好处。
设计实现的本质,知道仍是理解
操做系统是介于底层硬件和应用软件之间的接口,其各个子系统的实现很大程度上依赖于硬件特性。书上介绍这些子系统的设计和实现的时候,咱们读过了,也就知道了,若是再深刻考虑一下,为何总体架构要按照这种方式组织,为何局部函数要遵循这样的步骤处理,知其然,知其因此然,若是你知道了某个功能的实现是由于芯片就是这么设计的,CPU就是这么作的,那么你的疑问也就基本上到此为止了。再深究,就是芯片架构方面的设计与实现,对于程序员来说,不管是系统仍是应用程序员,足迹探究到这里,已经解决了不少疑问,由于咱们的工做性质偏软,而这些东西实在是够硬。
好比,ULK3中讲解的中断和异常的实现,究其根源,那是由于Intel x86系列就是这么设计的,去看看Intel V3手册中相应章节介绍,均可觉得ULK3中描述的代码实现方式找到注解。还有时间和定时器管理,一样能够在Intel V3 对APIC的介绍中获取足够的信息,操做系统就是依据这些硬件特性来实现软件方法定义的。
又是那句话,不是理解不理解的问题,而是知道不知道的问题。有时候,知道了,就理解了。在整个学习过程当中,知道,理解,知道,理解,知道……,交叉反复。为何开始和结尾都是知道,而理解只是中间步骤呢?世界上万事万物自有其规律,人类只是发现而已,实践是第一位的,实践就是知道的过程,实践产生经验,经验的总结就是理论,理论源于实践,理论才须要理解。咱们学习内核,深刻研究,搞来搞去,又回到了芯片上,芯片是物质的,芯片的功用基于天然界中物质本有的物理和电子特性。追本溯源,此之谓也。
动手写代码
纸上得来终觉浅,绝知此事要躬行。只看书是绝对不行的,必定要结合课本给出的编程建议本身敲代码。刚开始就以模块形式测试好了,或者本身编译一个开发版本的内核。一台机器的话,使用UML方式调试,内核控制路走到哪一步,单步调试看看程序执行过程,比书上的讲解更直观明了。必定要动手实际操做。
参考书
LDD3 Linux Device Driver 3rd
LKD3 Linux Kernel Development 3rd
ULK3 Understanding the Linux Kernel 3rd
PLKA Professional Linux Kernel Architecture
UML User Mode Linux
Intel V3 Intel? 64 and IA-32 Architectures Software Developer’s Manual Volume 3 (3A, 3B & 3C): System Programming Guide
做者在写书的时候,都是以本身的理解组织内容,从本身的观点看待一个主题,关注点跟做者自身有很大的关系。出书的时间有前后,后来人针对同一个主题想要出书而又不落入窠臼,最好有本身的切入方式,从本身的角度讲解相关问题,这才值得出这本书,千篇一概是个掉价的行为,书就不值钱了。
尽信书不如无书。
http://lwn.net/Articles/419855/ 此处是一篇关于LKD3的书评,指出了其中的错误,当你读完的时候,不妨去找找,看一下本身在其中所描述的地方有什么特别的印象。
http://lwn.net/Articles/161190/此处是一篇对ULK3的介绍,我认为其中很关键的几句话就能够给本书定位:
Many of the key control paths in the kernel are described, step by step;
一步一步地讲述内核控制路径的实现。
The level of detail sometimes makes it hard to get a sense for the big picture, but it does help somebody trying to figure out how a particular function works.
对代码讲解的详细程度有时候很难让读者把握住它的主旨大意,可是确实有助于读者理解一个特定的函数究竟是如何工做的。
Indeed, that is perhaps the key feature which differentiates this book. It is very much a “how it works” book, designed to help people understand the code.
事实上,这也正是本书不同凡响的地方。更像一个“如何工做”的书,帮助读者理解代码实现。
It presents kernel functions and data structures, steps the reader through them, but does not, for example, emphasize the rules for using them. UTLK is a study guide, not a programming manual.
本书描述了内核函数和数据结构,引导读者穿行于其间,可是,并无着重强调使用它们的法则。UTLK是一本学习指南,而不是编程手册。
这几句话对本书的描述很是到位。基于此,做为指导性原则,咱们就能够颇有效率地使用它了。
看一本技术书籍,书中的序言部分绝对是首先应该翻阅的,其次就是目录。我发如今阅读过程当中我会频繁的查看目录,甚至是喜欢看目录。
结尾
兴趣的力量是无穷的。兴趣能带来激情,若是工做能够和兴趣结合到一块儿,工做起来才会有热情,那么工做就不仅是工做了,更是一种享受。
Linux,个人兴趣,个人动力,个人方向,个人将来!
来源:冰凌块儿
blog.chinaunix.net/uid-24669930-id-4039377.html