内核这么坚硬,当初你是怎么一步步达到现在市面上的要求的,其中应该有些血泪吧。


步入殿堂,我的理解就是自己能靠这手艺养活自己,不仅饿不死,还有碗饱饭吃。对于资质平平的普通人来说,这也不难,就是坚持和时间的问题。大家看到的高手都是聪明人,他们不做内核开发做其他工作也会是很牛X,我们这些普通人之所以说要坚持和时间,是因为我们不管做什么事情,能有口饱饭吃都得靠坚持和时间。

内核开发也是写软体代码,和其他的软体代码开发工作没啥区别:创造有人用的代码。这就是一份工作,把工作做好,领薪水买米面油气交房前。可能不同的是内核软体没有用户界面,普通用户没法直接看到效果。

这份工作的好处是稳定和灵活,因为市场上工作岗位数量远远超过从事内核开发的聪明人,所以普通人如果能够达到基本的工作要求,也可以得到一份稳定而且灵活的工作。

稳定是指,薪水比较稳定,岗位也比较稳定,不会出现短期内快速加薪升职的情况。灵活是指,有很多此类岗位是可以提供远程办公的,所以如果不强求留在北上广深,而是回到老家和家里人一起生活,找一个彼此相爱的人厮守,这份薪水可以在当地过上娇纵淫欲的生活妥妥没问题。此外,只要能完成工作,时间都是自己安排的。如果真想做内核开发(其实绝大多数人并不感兴趣),这种氛围还是很有助于能力的成长的。

聪明人的例子就不说了,扎心。大家分享一下我自己这个普通人是如何走上做内核开发这条路,还至今没有饿死的。

我是97年上的大学,学校比较一般,刚入学的时候我满脑子想的是如何毕业之后和老家亲戚们一起经营农村土特产。大概是大二下学期有一次在图书馆看书,无意中看到了一本介绍Linux的薄书,作者写的很有意思,我居然就在图书馆一直看到很晚把那本书给看完了。然后我就决定,要去找Linux来玩玩。当时学校的机房里还没有Linux,我自己也没有电脑,只能是残念了。后来大三暑假我去了一家叫美商网虎的Linux公司实习,算是真正接触了这个系统,感觉很酷。关键是编程也是黑屏幕和我学DOS编程的环境很像,上手很顺利,呵呵。再后来就是在沈树镛教授指导下,在学校计算中心开课跟大家介绍这个系统的使用,自己也利用计算中心的网路环境和设备环境,很深入的了解了这个系统的使用和配置,以及基本的编程概念。

然后就开始进去了学习Linux内核编程的大坑,哈哈,什么不懂学什么,一转眼就十几年过去了。从驱动开始做起,然后做应用,然后做系统管理工具,然后做文件系统,然后去互联网公司做了几年工程管理,现在又回到一线岗位继续做Linux内核开发。

一眨眼,从我98年第一次知道Linux到现在,已经20年过去了。现在还能依然靠开发Linux内核养家糊口,还把自己吃成了胖子,我觉得已经蛮开心了。如果把这种状态称之为步入殿堂的哈,可能最重要的一条就是不要放弃自己。Linux内核代码是由一群优秀的工程师开发的,里面还会尝尝夹杂很多其它领域专业知识。普通开发者(譬如我)看不懂或者需要学习其它知识是家常便饭,时时会觉得自己和其他开发者比起来简直就是一头蠢猪,做这一行完全不适合没出路。这种感觉会经常冒出来 然而,对于系统软体开发的喜爱是由心而生的,随著越来越深入,我也么逐渐接受了自己没有预期那么优秀的现实,并鼓励自己蠢也不妨碍我喜欢这个技术

做Linux内核开发和其他软体开发差别不太大,要做到优秀都是要付出努力的,没什么高低之分。这毕竟只是一份工作,要认真对待,但它也不是生活的全部。作为一个工程师,一个中国人,如果通过参与这个技术,从很具体的细节做起,让生活更美好,让世界更美好,让我们彼此之间更和谐,这是很有乐趣的事情,也是我认识的很多比我优秀的多的内核开发者们发自内心的动力。

上图右一胖子是本人。

系统软体开发,坦诚说并不适合绝大多数人,但如果有缘能够参与其中,养家糊口没问题的。如果有朋友觉得好难,或者好苦,只要你还喜欢就不要放弃。你不孤单,还有很多「蠢货」和你一样,一边挠头苦逼,一边傻乐傻笑


内核没有什么殿堂,也并不高大上。相反的, 我更多的时候看到的是搞内核的人视野很狭窄,技术很单调,跳出内核什么都不懂。

伪内核高手的典型特征是:

1 不懂用户态。(是的, 不懂用户态的人本质上也不懂内核)

2 只会C这种最基础最初级的语言,拒绝学习其它OO语言。殊不知,内核虽然是C,但是也处处在采用OO 的写法。学习下高级语言拓展思维非常必要。

3 认为Linux是优雅的设计和实现。其实并不是,Linux的糟粕跟所谓的精华一样多。比如Linux的进线程设计是很模糊的,一点都不清晰。但其它平台则划分的更清晰更自然。再比如Windows的结构化异常处理,可以说是一大创举,Linux党没几个人懂。内核里最复杂的部分, 早就不是什么内存管理,进程调度了。其实GUI才是最复杂最有挑战的,Linux在这个领域跟win和mac 完全没有可比性。mac os 虽然开源,但是你看他舍得公开gui部分吗?

4 从代码层面讲,Linux的代码也很垃圾。我认为Linux内核连最起码的命名都没有做好。比如 local_irq_save , 真的是 save 吗 ? 其实应该是 local_irq_disable_and_saveget_cpu 单看这函数名,你能想到其实是个关闭抢占? 同样的函数名,到了kvm里又是另一个含义。在用户态,发信号的函数起名叫 kill, 要杀人还是咋地? 整数除0 会报错成 float point 异常。呵呵。

那么想成为真正的Linux内核高手应该怎么做呢 ?

1 学习体系结构。保护模式都几十年了,很多人对基本的运行环境切换,页表管理,内存分页分段,系统调用都搞不清楚。Intel 手册第三卷 system programming guide 不敢说通读,至少关键问题需要完整看一遍。不然连个自旋锁原理都搞不清楚。

2 学习编译原理。我这里说的编译原理,不是常规的前端词法分析,语法分析,语义分析,语法树生成。其实更主要的是后端。后端才是衔接操作系统的部分。指令选择,指令调度,寄存器分配跟前面说的体系结构关联紧密,相辅相成,可以互相促进理解。另外,编译跟装载又是一起的,而程序的装载又是跟进线程的初始化,内存管理紧密相关的。只有把这部分彻底融会贯通才算打通任督二脉。发明UNIX操作系统的两位老先生,你当人家只会搞内核?Ritchie发明了C语言,还写过编辑器。编译器前端离不开的状态机构造技术,Thompson构造法就是Thompson发明的,人家现在还在搞go 语言。从根本上讲,软体做的事情90%以上都是形式转化,而编译器融合了形式转化的大部分精华。错过编译器技术的人都不知道自己错过了什么。

3 debug,解决难题。Linux内核的书遍地都是,代码触手可得。不是说你看看书,读读代码就搞懂东西了。读来的东西太浅,写东西才会理解深刻。我对内核理解最深刻的部分,全都是在调试器里一行一行汇编跟踪过的部分,多少年不搞了都忘不了。linux内核里各种奇葩的条件编译和嵌套的宏定义往往会隐藏真相,万事不过debug。多debug 可以更好的理解系统的ABI, 了解编译器对代码的处理,了解系统结构实现的细节。说到这里,又跟前面提到的两点结合起来了。

4 拓展知识面。只看Linux内核局限还是很明显。比如Linux的中断可以嵌套,这是为了更大的IO吞吐。而Win的中断有优先顺序,高优先顺序中断不被低优先顺序中断打断,这是为了更好的桌面体验。那么MAC 是什么选择呢? 比如Linux 对异常的处理就是发信号,那Win是分层的结构化的异常回调机制,哪个更好呢?再比如,PC上的操作系统,硬体抽象层(HAL)都在内核里,而Android却把HAL做到了用户层,这是为什么呢?到了内核的各个子系统,可对比的就更多了。搞Linux内核的人完全可以看看windows research kernel 的代码。如果你们真的看明白了,你们就会明白微软作为一个靠敲代码敲出来的帝国,不是白给的。

殿堂? 不存在的,只有苦行僧。


首先, 先不要神话内核开发. 就是读代码, 改, 调试. 几个月下来你就熟悉某一个小模块了. 要知道, 很多人并不真的会写c语言, 不妨碍他们读, 改, 调内核.

比如我就面过mtk里做蓝牙驱动开发, 愣是没写出strlen(). 这种大一C语言就不合格的人(是不合格, 不是不及格), 最后成为了开发者, 是非常常见的.


目前的工作实际上不是在搞 Linux 内核,但读大学的 4 年,其中有两年的时间在研究 Linux 内核和嵌入式 Linux。虽然已经好多年没再搞 Linux 内核,但上次项目需要,还是分析调试了 Android 的 low memory killer 驱动,并给 Android 的 binder 驱动增加了一些功能,对于 Linux 的内核的基本分析调试能力一直在。看到这个问题,分享一下自己的做法。

以我的理解,题主的问题可以分解为三个小问题,Linux 内核开发需要知道的基本背景知识,Linux 内核开发研究在技术上的路线图,以及 Linux 内核开发过程中的分析调试手法。

Linux 内核开发需要的基本背景知识。为什么说是「基本」呢?主要是因为,如我们从操作系统原理一棵中所知道的那样,操作系统内核都是分为基本大的子系统的,如 I/O,任务调度,内存管理,文件系统和网路等等,这些子系统都是演算法密集型的系统,不同子系统需要的背景知识还不太一样。

Linux 内核主要是用 C 语言写的,因而 C 语言开发的基本功必不可少。C 语言开发学习的经典著作很多,不仅有 C程序设计语言 这样长生不衰的权威之作,还有,还有「C 语言开发的四书五经」和 C 语言开发——现代方法 这些非常好的作品。操作系统内核作为一个数据结构和演算法密集型的领域,基本的数据结构和演算法知识不可或缺,数据结构 这本必修课自不必说,其它还有演算法导论等等经典。

想要研究 Linux 内核,站在用户的角度来看待它,了解它的功能和介面是必须的。谁是 Linux 内核的用户,Linux 内核又为用户提供了什么功能,用户又是通过什么介面访问这些功能的呢?Linux 内核功能主要是通过系统调用暴露给用户的,系统调用通常又被封装为 C 库,需要使用操作系统内核功能的开发者通过 C 库使用 Linux 内核。相关领域非常经典的著作是 UNIX环境高级编程(第3版),读了这本书,应该就大体可以了解到,操作系统提供的大概就是文件操作,进程线程操作等功能了。程序员的自我修养 也值得一看,可以了解一下程序载入运行的过程。

然后是操作系统原理和计算机体系结构。用户空间看到的操作系统功能和操作系统内部通常的设计结构并非严格对应的。通过操作系统原理,可以让我们看到操作系统内部通常的设计结构,如通常的子系统划分, I/O,任务调度,内存管理,文件系统和网路等,多个子系统的功能,都按照「一切皆文件」的 Unix 系统经典理念,通过文件有关的介面暴露给用户空间。操作系统原理有关的经典著作有斯托林斯的 操作系统——精髓与设计原理,Andrew S·Tanenbaum 的 现代操作系统和操作系统设计与实现等,其中 操作系统设计与实现 还是 Linus 当年设计实现 Linux 内核时的主要参考。UNIX操作系统设计 和 Linux内核设计与实现 也非常经典,值得一读,Linux内核设计与实现 的作者是 Linux 内核的核心开发者,还是内核抢占子系统的作者。自己动手写操作系统 也可以看一下。

Linux 内核研发是一个软硬体结合的领域,计算机组成原理和体系结构相关的知识必不可少,汇编语言,CPU 的 MMU 等等都需要有所了解。相关的经典著作有 深入理解计算机系统 、计算机组成与设计硬体/软体介面、ARM嵌入式系统开发 和 MIPS体系结构透视 等。答住过去关注的主要硬体平台是 ARM 的,因而关于 X86 平台的介绍,可以自行找涵盖了 MMU/保护模式 的 X86 汇编语言有关的著作来研究。

Linux 内核开发需要的基本背景知识大概就是这些。

Linux 内核开发研究在技术上的路线图。首先当然是从能够快速上手,能够快速带来成就感的地方开始。硬体平台可以用自己日常使用的 PC 机,装上 Linux 发行版,安装必要的编译链接等开发工具,差不多就可以上手了。Linux 内核的文档非常齐全,可以用 Git 把 Linux 内核的源码整个下载到本地,然后编译一下,熟悉熟悉 Linux 内核的构建系统,毕竟在整个的 Linux 内核研发过程中需要与这套系统打交道的地方很多。

就 Linux 内核研究和开发本身来说,最简单最方便的入手点就是驱动程序了。驱动程序可以从简单的字元设备内存型驱动开始,编写一个 「Hello world」字元设备驱动,暴露基本的文件操作,编译并动态载入进内核,在通过文件操作访问它时,可以让它仅仅列印一个「Hello world」。当然内核不能使用 C 语言标准库,内核列印的信息也不通过终端来看,而是通过 dmesg 命令来看。据说当前大多数的 Linux 内核研发工程师所做的工作,都是在搞驱动,驱动相关的代码在 Linux 内核代码中的占比远超一半。介绍 Linux 内核驱动的书很多,经典的长盛不衰但有点老的有 Linux设备驱动程序,还有 Linux设备驱动开发详解 和 精通Linux驱动程序开发 等值得一读。实际的 Linux 内核驱动当然不可能像「Hello world」字元设备驱动那么简单。实际编写驱动时,硬体设备本身的协议需要仔细研读,诸如硬体设备有几个寄存器或者 IO 埠,对这些寄存器和 IO 埠的不同访问方式可以访问到什么功能等等。此外在 Linux 内核中运行的驱动程序代码,与内核中的其它子系统的交互几乎是必不可少的,因而 Linux 驱动相关的书读下来,会发现大部分都在讲内核中的内存分配和管理,Linux 内核中的并发同步方法等等。嵌入式 Linux 系统有关的书会讲许多关于硬体访问方法的内容,值得一读,如 嵌入式Linux应用开发完全手册, ARM嵌入式系统基础教程,嵌入式Linux基础教程

很长时间没有通过读书来学习研究 Linux 内核,最近新出的书就不太了解了。不过在有了一定的基础之后,研究 Linux 内核最好的方法就是,阅读 Linux 内核官方相关模块的文档说明,阅读 Linux 内核的代码,然后做一些调试了。

研究学习 Linux 内核,除了从驱动入手外,也可以从另外两个点入手,一是内核的启动过程,二是系统调用。内核启动和系统调用也都是离用户最近的点,相对比较容易我们著手分析调试。

能够上手写一些 Linux 内核代码,并对 Linux 内核开发中能够用到的工具,如 Linux 内核提供的同步的函数,内存分配管理的函数等基础有所了解之后,就可以根据自己的喜好和项目需要,来具体深入学习研究特定子系统了,如任务调度,内存管理,文件系统和网路等等。

总结一下,Linux 内核开发研究在技术上的路线图大概是这样的:代码下载和构建 -&> 选择从 Linux 驱动、内核的启动过程或系统调用三者之一入手开始自己的内核开发之旅 -&> 学习 Linux 内核开发中能用到的工具和函数库 -&> 根据工作和项目需要,选择某个自己感兴趣的子系统,如任务调度,内存管理,文件系统、IO、设备驱动和网路等等深入研究,完成自己的工作。

Linux 内核开发过程中的分析调试手法。硬体平台可以用自己的 PC 机,装上 Linux 发行版,然后在上面做实验。也可以用 ARM 平台做为硬体平台,可以买一块 ARM 开发板或者 Google 的 Nexus 系列手机。用 Google 的 Nexus 系列手机时,可以参考 Google 提供的官方文档来构建内核。不用硬体,用模拟器或虚拟机更方便,还不用担心把电脑或手机变成砖。Android 模拟器用来研究 Linux 内核非常方便。分析调试可以通过打断点或者列印日志来做。用 Android 模拟器来打内核的断点比较方便。

最后,乐者为王 是一本介绍 Linus 的书,非常有意思。关于 Unix 社区的一些文化和哲学有关的内容可以经常看一下。


被称作「内核工程师」的其实有很多分类

  • 大多数都是做驱动的,特别是嵌入式。这个基本靠熟悉相关模块的代码,自己搞个out-of-tree module代码质量也没什么要求,能跑就行 (抱歉,但看过的搞嵌入式的人写的driver真的不敢恭维……)
  • 做相关上下游的时候顺便修修bug提交给上游的,例如做cloud/virtualization碰到kernel bug挂了自己修一修。这个基本都集中在大厂的infra,部分不够大的厂的号称的「内核组」也做这个
  • 为了版本/ABI/.../稳定,维护自己的kernel版本,裁剪/backport需要的功能的,常见于大厂内核组,redhat在部分程度上也属于这类,大厂内部一般也有专门的team做这个
  • 需要新的功能,能够影响kernel开发方向的。这个看看linux foundation成员和Linux plumber conf都是哪些人就能知道了,因为加新功能是一个政治问题,不仅仅是个技术问题。fb和g家都有百人左右的内核团队,最近搞的ebpf, xdp都属于此类。由于内核团队的小圈子特性,最好认识相关的前辈可以带你进入社区


推荐阅读:
相关文章