《2022年Linux操作系统源代码详细分析 .pdf》由会员分享,可在线阅读,更多相关《2022年Linux操作系统源代码详细分析 .pdf(14页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、linux 源代码分析 :Linux 操作系统源代码详细分析疯狂代码 http:/CrazyC ?:http:/CrazyC 内容介绍 : Linux 拥有现代操作系统所有功能如真正抢先式多任务处理、支持多用户内存保护虚拟内存支持SMP 、UP 符合POSIX 标准联网、图形用户接口和桌面环境具有快速性、稳定性等特点本书通过分析Linux 内核源代码充分揭示了 Linux 作为操作系统内核是如何完成保证系统正常运行、协调多个并发进程、管理内存等工作现实中能让人自由获取系统源代码并不多通过本书学习将大大有助于读者编写自己新 第部分 Linux 内核源代码 arch/i386/kernel/ent
2、ry.S 2 arch/i386/kernel/init_task.c 8 arch/i386/kernel/irq.c 8arch/i386/kernel/irq.h 19 arch/i386/kernel/process.c 22 arch/i386/kernel/signal.c 30arch/i386/kernel/smp.c 38 arch/i386/kernel/time.c 58 arch/i386/kernel/traps.c 65arch/i386/lib/delay.c 73 arch/i386/mm/fault.c 74 arch/i386/mm/init.c 76 fs
3、/binfmt-elf.c 82fs/binfmt_java.c 96 fs/exec.c 98 /asm-generic/smplock.h 107 /asm-i386/atomic.h 108 /asm-i386/current.h 109 /asm-i386/dma.h 109 /asm-i386/elf.h 113 /asm-i386/hardirq.h 114 /asm-i386/page.h 114 /asm-i386/pgtable.h 115 /asm-i386/ptrace.h 122 /asm-i386/semaphore.h 123 /asm-i386/shmparam.
4、h 124 /asm-i386/sigcontext.h 125 /asm-i386/siginfo.h 125 /asm-i386/signal.h 127/asm-i386/smp.h 130 /asm-i386/softirq.h 132 /asm-i386/spinlock.h 133 /asm-i386/system.h 137/asm-i386/uaccess.h 139 /binfmts.h 146 /capability.h 147 /linux/elf.h 150 /linux/elfcore.h 156/linux/errupt.h 157 /linux/kernel.h
5、158 /linux/kernel_stat.h 159 /linux/limits.h 160 /linux/mm.h 160/linux/module.h 164 /linux/msg.h 168 /linux/personality.h 169 /linux/reboot.h 169 /linux/resource.h170 /linux/sched.h 171 /linux/sem.h 179 /linux/shm.h 180 /linux/signal.h 181 /linux/slab.h 184/linux/smp.h 184 /linux/smp_lock.h 185 /lin
6、ux/swap.h 185 /linux/swapctl.h 187 /linux/sysctl.h 188/linux/tasks.h 194 /linux/time.h 194 /linux/timer.h 195 /linux/times.h 196 /linux/tqueue.h 196/linux/wait.h 198 init/.c 198 init/version.c 212 ipc/msg.c 213 ipc/sem.c 218 ipc/shm.c 227 ipc/util.c236 kernel/capability.c 237 kernel/dma.c 240 kernel
7、/exec_do.c 241 kernel/exit.c 242 kernel/fork.c 248kernel/info.c 255 kernel/itimer.c 255 kernel/kmod.c 257 kernel/module.c 259 kernel/panic.c 270kernel/prk.c 271 kernel/sched.c 275 kernel/signal.c 295 kernel/softirq.c 307 kernel/sys.c 307kernel/sysctl.c 318 kernel/time.c 330 mm/memory.c 335 mm/mlock.
8、c 345 mm/mmap.c 348mm/mprotect.c 358 mm/mremap.c 361 mm/page_alloc.c 363 mm/page_io.c 368 mm/slab.c 372mm/swap.c 394 mm/swap_state.c 395 mm/swapfile.c 398 mm/vmalloc.c 406 mm/vmscan.c 409 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 14 页 - - - - - - - - - 第 2
9、 部分 Linux 内核源代码分析 第1章 Linux 介绍 让用户很详细地了解大多数现有操作系统实际工作方式是不可能大多数操作系统源代码都是严格保密除了些研究用及为操作系统教学而设计系统外尽管研究和教学目都很好但是这类系统很少能够通过对正式操作系统小部分实现来体现操作系统实际功能对于操作系统些特殊问题这种折衷系统所能够表现就更是少得可怜了 在以实际使用为目标操作系统中让任何人都可以自由获取系统源代码无论目是要了解、学习还是改进这样现实系统并不多本书主题就是这些少数操作系统中个:Linux Linux工作方式类似于 Uinx它是免费源代码也是开放符合标准规范标准32位( 在64位CPU 上是6
10、4位) 操作系统 Linux 拥有现代操作系统所具有内容例如: * 真正抢先式多任务处理支持多用户 * 内存保护 * 虚拟内存 * 支持对称多处理机SMP(symmetric multiprocessing)即多个 CPU 机器以及通常单 CPU(UP) 机器 * 符合POSIX 标准 * 联网 * 图形用户接口和桌面环境 ( 实际上桌面环境并不只个) * 速度和稳定性 严格说来 Linux 并不是个完整操作系统当我们在安装通常所说 Linux 时我们实际安装是很多工具集合这些工具协同工作以组成个功能强大实用系统Linux 本身只是这个操作系统内核是操作系统心脏、灵魂、指挥中心( 整个系统应该
11、称为 GNU/Linux其原因在本章后续内容中将会给以介绍 ) 内核以独占方式执行最底层任务保证系统正常运行协调多个并发进程管理进程使用内存使它们相互的间不产生冲突满足进程访问磁盘请求等等 在本书中我们给大家揭示就是Linux 是如何完成这具有挑战性工作 1.1 Linux和Unix简明历史 为了让大家对本书所讨论内容有更清楚了解让我们先来简要回顾下Linux 历史由于 Linux 是在Unix基础上发展而来我们话题就从Unix开始 Unix 是由AT&T 贝尔实验室 KenThompson 和Dennis Ritchie于1969年在台已经废弃了 PDP-7 上开发;它最初是个用汇编语言写成
12、单用户操作系统不久 Thompson 和Ritchie 成功地说服管理部门为他们购买更新机器以便该开发小组可以实现个文本处理系统Unix就在PDP-11 上用C语言重新编写 ( 发明C语言部分目就在于此 ) 它果真变成了个文本处理系统不久的后只不过问题是他们先实现了个操作系统而已 最终他们实现了该文本处理工具而且Unix( 以及Unix上运行工具) 也在AT&T 得到广泛应用在 1973年Thompson 和Ritchie 在个操作系统会议上就这个系统发表了篇论文该论文引起了学术界对 Unix系统极大兴趣 由于1956年反托拉斯法案限制 AT&T 不能涉足计算机业务但允许它象征性地收取费用发售
13、该系统就这样Unix被广泛发布首先是学术科研用户后来又扩展到政府和商业用户 伯克利加州大学是学术用户中个在这里Unix得到了计算机系统研究小组(CSRG) 广泛应用并且在这里所进行修改引发了Unix大系列这就是广为人知伯克利软件Software 开发(BSD)Unix除了AT&T 所提供 Unix系列的外 BSD 是最有影响力Unix系列BSD 在Unix中增加了很多显著特性例如TCP/IP网络更好用户文件系统 (UFS)工作控制并且改进了AT&T 内存管理代码 多年以来 BSD 版本Unix直在学术环境中占据主导地位但最终发展成为 V版本AT&TUnix 则成为商业领域领头羊从某种程度上来说
14、这是有社会原因: 学校倾向于使用非正式但通常更好用BSD 风格Unix而商业界则倾向于从 AT&T 获取Unix 在用户需求和用户编程改进特性促进下BSD 风格Unix般要比 AT&TUnix 更具有创新性而且改进也更为迅速但是在AT&T 发布最后个正式版本 V Release 4(SVR4) 时 V Unix 已经吸收了 BSD 大多数重要优点并且还增加了些自己优势这部分由于从1984年开始 AT&T 逐渐可以将 Unix商业化而伯克利 Unix开发工作在 1993年BSD4.4 版本完成以后就逐渐收缩以至终止了然而BSD 进步改进由外界开发者延续下来到今天还在继续进行正在进行 Unix系列
15、开发中至少有 4 个独立版本是直接起源于BSD4.4 这还不包括几个厂商 Unix版本例如惠普 HP-UX 都是部分地或者全部基于BSD 而发展起来 实际上 Unix变种并不止 BSD 和 V由于Unix主要使用 C语言来编写这就使得它移植到新机器上相对比较容易它简单性也使其重新设计和开发相对比较容易Unix这些特点名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 14 页 - - - - - - - - - 大受商业界硬件供应商欢迎比如Sun、SGI、HP 、IBM、DE
16、C 、Amdahl等等; IBM还不止次对 Unix进行了再开发厂商们设计开发出新硬件并简单地将Unix移植到新硬件上这样新硬件经发布便具备定功能经过段时间的后这些厂商都拥有了自己专有Unix版本而且为了占有市场这些版本故意以区别侧重点发布出来以更好地占有用户版本混乱状态促进了标准化工作进行其中最主要就是POSIX 系列标准它定义了套标准操作系统接口和工具从理论上说 POSIX 标准代码很容易移植到任何遵守POSIX 标准操作系统中而且严格POSIX 测试已经把这种理论上可移植性转化为现实直到今天几乎所有正式操作系统都以支持POSIX 标准为目标 现在让我们回顾下在 1984年杰出电脑黑客 R
17、ichard Stallman独立开发出个类 Unix操作系统该操作系统具有完全内核、开发工具和终端用户应用在GNU( “GNU 誷 Not Unix ”首字母缩写 ) 计划配合下 Stallman 开发这个产品有自己技术理想: 他想开发出个质量高而且自由操作系统Stallman 使用了“自由” (free)这个词不仅意味着用户可以免费获取软件Software ;而且更重要是它将意味着某种程度“解放”: 用户可以自由使用、拷贝、查询、重用、修改甚至是分发这份软件 Software 完全没有软件 Software 使用限制这也正是 Stallman 创建自由软件 Software 基金会 (FS
18、F)资助GNU 软件Software 开发本意 (FSF也在资助其他科研方面开发工作) 15 年来GNU 工程已经吸收、产生了大量这不仅包括 Emacs 、gcc(GNUC 编译器 ) 、bash(shell 命令) 还有大部分 Linux 用户所熟知许多应用现在正在进行开发项目是 GNU Hurd 内核这是 GNU 操作系统最后个主要部件( 实际上 Hurd内核早已能够使用了不过当前版本号为0.3 系统在什么时候能够完成还是未知数) 尽管Linux 大受欢迎但是 Hurd内核还在继续开发原因有几个方面其是Hurd体系结构十分清晰地体现了Stallman 有关操作系统工作方式思想例如在运行期间
19、任何用户都可以部分地改变或替换Hurd(这种替换不是对每个用户都是可见而是只对申请修改用户可见而且还必须符合规范标准) 另个原因是据介绍 Hurd对于多处理器支持比 Linux 本身内核要好还有个简单原因是兴趣驱动员们希望能够自由地进行自己所喜欢工作只要有人希望为Hurd工作Hurd开发就不会停止如果他们能够如愿以偿Hurd有朝日将成为 Linux 强劲对手不过在今天 Linux 还是自由内核王国里无可争议统治者 在GNU 发展中期也就是 1991年个名叫 Linus Torvalds芬兰大学生想要了解Intel 新CPU 80386他认为比较好学习思路方法是自己编写个操作系统内核出于这种目加
20、上他对当时Unix变种版本对于 80386类机器脆弱支持十分不满他决定要开发出个全功能、支持POSIX 标准、类 Unix操作系统内核该系统吸收了 BSD 和 V优点同时摒弃了它们缺点Linus( 虽然我知道我应该称他为Torvalds 但是所有人都称他为Linus) 独立把这个内核开发到 0.02版这个版本已经可以运行gcc、bash和很少些应用这些就是他开始全部工作了后来他又开始在因特网上寻求广泛帮助 不到 3 年LinusUnix Linux 已经升级到 1.0 版本它源代码量也呈指数形式增长实现了基本 TCP/IP功能( 网络部分代码后来重写过而且还可能会再次重写) 此时Linux 就
21、已经拥有大约10万用户了 现在Linux 内核由 150多万行代码组成 Linux 也已经拥有了大约 1000万用户 ( 由于Linux 可以自由获取和拷贝获取具体统计数字是不可能)Linux 内核GNU/Linux附同GNU 工具已经占据了 Unix 50%市场些公司正在把内核和些应用同安装软件Software 打包在起生产出 Linux 发行版本这些公司包括 Red Hat和Caldera 公司现在GNU/Linux已经备受瞩目得到了诸如Sun、IBM、SGI等公司广泛支持 SGI最近决定在其基于 IntelMerced 系列机器上不再搭载自己 Unix变种版本 IRIX而是直接采用 GN
22、U/Linux;Linux 甚至被指定为 Amiga将要发布新操作系统基础 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 14 页 - - - - - - - - - 1.2 GNU 通用公共许可证 这样个如此流行操作系统当然值得我们学习按照通用公共许可证(GPLGeneralPublic License)规定Linux 源代码可以自由获取这满足了我们学习该系统强烈愿望GPL 这份非同寻常软件Software 许可证充分体现了上面提到Stallman 思想: 只要用户所
23、做修改是同等自由用户可以自由地使用、拷贝、查询、重用、修改甚至重新发布这个软件Software 通过这种方式 GPL 保证了 Linux( 以及同许可证保证下大量其他软件 Software) 不仅现在自由可用而且以后经过任何修改的后都仍然可以自由使用 请注意这里自由并不是说没有人靠这个软件 Software 盈利有些日益兴起公司比如发行最流行Linux 发行版本 Red Hat就是个例子 (RedHat自从上市以来市值已经突破数十亿美元每年盈利数十万美元而且这些数字还在不断增长) 但是任何人都不能限制其他用户涉足本软件Software 领域而且所做修改不能减少其自由程度 本书附录 B中收录了
24、GNU 通用公共许可证全文 1.3 Linux 开发过程 如上所述由于 Linux 是个自由软件 Software 它可以免费获取以供学习研究Linux 的所以值得学习研究是它是相当优秀操作系统如果Linux 操作系统相当糟糕那它就根本不值得我们使用也就没有必要去研究相关书籍 Linux 是个十分优秀操作系统还在于几个相互关联原因 原因的在于它是基于天才思想开发而成在学生时代就开始推动整个系统开发Linus Torvalds是个天才他才能不仅展现在编程能力方面而且组织窍门技巧也相当杰出 Linux 内核是由世界上些最优秀员开发并不断完善他们通过Internet相互协作开发理想操作系统;他们享受
25、着工作中乐趣而且也获得了充分自豪感 Linux 优秀另外个原因在于它是基于组优秀概念Unix是个简单却非常优秀模型在 Linux 创建的前 Unix已经有 20年发展历史 Linux 从Unix各个流派中不断吸取成功经验模仿Unix优点抛弃Unix缺点这样做结果是 Linux 成为了 Unix系列中佼佼者 : 高速、健壮、完整而且抛弃了历史包袱 然而Linux 最强大生命力还在于其公开开发过程每个人都可以自由获取内核源每个人都可以对源加以修改而后他人也可以自由获取你修改后源如果你发现了缺陷你可以对它进行修正而不用去乞求不知名公司来为你修正如果你有什么最优化或者新特点创意你也可以直接在系统中增加
26、功能而不用向操作系统供应商解释你想法指望他们将来会增加相应功能当发现个漏洞后你可以通过编程来弥补这个漏洞而不用关闭系统直到你供应商为你提供修补由于你拥有直接访问源代码能力你也可以直接阅读代码来寻找缺陷或是效率不高代码或是安全漏洞以防患于未然 除非你是个员否则这点听起来仿佛没有多少吸引力实际上即使你不是员这种开发模型也将使你受益匪浅这主要体现在以下两个方面 : * 可以间接受益于世界各地成千上万员随时进行改进工作 * 如果你需要对系统进行修改你可以雇用员为你完成工作这部分人将根据你需求定义单独为你服务可以设想这在源不公开操作系统中将是什么样子Linux 这种独特自由流畅开发模型已被命名为baza
27、ar( 集市模型 ) 它是相对于 cathedral(教堂) 模型而言在cathedral 模型中源代码被锁定在个保密小范围内只有开发者( 很多情况下是市场 ) 认为能够发行个新版本这个新版本才会被推向市场这些术语在Eric S. Raymond 教堂和集市 (The Cathedral and the Bazaar)文中有所介绍大家可以在 http:/www.tuxedo.org/esr/writings/找到这篇文章 bazaar开发模型通过重视实验征集并充分利用早期反馈对巨大数量脑力资源进行平衡配置可以开发出更优秀软件Software( 顺便说下虽然 Linux 是最为明显使用bazaa
28、r开发模型例子但是它却远不是第个使用这个模型系统) 为了确保这些无序开发过程能够有序地进行Linux 采用了双树系统个树是稳定树(stable tree)另个树是非稳定树 (unstable tree)或者开发树 (developmenttree) 些新特性、实验性改进等都将首先在开发树中进行如果在开发树中所做改进也可以应用于稳定树那么在开发树中经过测试以后在稳定树中将进行相同改进按照Linus 观点旦开发树经过了足够发展开发树就会成为新稳定名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - -
29、 第 4 页,共 14 页 - - - - - - - - - 树如此周而复始进行下去 源版本号形式为 x.y.z 对于稳定树来说 y是偶数;对于开发树来说y比相应稳定树大 ( 因此是奇数 ) 截至到本书截稿时最新稳定内核版本号是2.2.10 最新开发内核版本号是 2.3.12 对2.3 树缺陷修正会回溯影响(back-propagated)2.2树而当 2.3 树足够成熟时候会发展成为2.4.0( 顺便说下这种开发会比常规惯例要快每版本所包含改变比以前更少了内核开发人员只需花很短时间就能够完成个实验开发周期)http:/www.kernel.org及其镜像站点提供了最新可供内核版本而且同时包
30、括稳定和开发版本如果你愿意话不需要很长时间这些站点所提供最新版本中就可能包含了你部分源代码 第2章 代 码 初 识 本章首先从较高层次介绍Linux 内核源概况这些都是大家关心些基本特点随后将简要介绍些实际代码最后介绍如何编译内核 2.1 Linux内核源部分特点 在过去段时期 Linux 内核同时使用 C语言和汇编语言来实现这两种语言需要定平衡:C语言编写代码移植性较好、易于维护而汇编语言编写则速度较快般只有在速度是关键原因或者些因平台相关特性而产生特殊要求( 例如直接和内存管理硬件进行通讯) 时才使用汇编语言 正如实际中所做即使内核并未使用C对象特性部分内核也可以在g(GNUC 编译器 )
31、 下进行编译同其他面向对象编程语言相比较相对而言 C开销是较低但是对于内核开发人员来说这已经是太多了 内核开发人员不断发展编程风格形成了Linux 代码独有特色本节将讨论其中些问题 2.1.1 gcc特性使用 Linux 内核被设计为必须使用 GNUC编译器gcc来编译而不是任何种 C编译器都可以使用内核代码有时要使用gcc特性本书将陆续介绍其中部分 些gcc特有代码只是简单地使用 gcc语言扩展例如允许在 C(不只是 C)中使用 inline关键字指示内联也就是说代码中被在每次时都会被扩充因而就可以节约实际开销 般情况下代码编写方式比较复杂对于某些类型输入gcc能够产生比其他输入效率更高执行
32、代码从理论上讲编译器可以优化具有相同功能两种对等思路方法并且得到相同结果因此代码编写方式是无关紧要但在实际上用某种思路方法编写所产生代码要比用另外些思路方法编写所产生代码执行速度快许多内核开发人员知道怎样才能产生更高效执行代码这不断地在他们编写代码中反映出来 例如考虑内核中经常使用 goto语句为了提高速度内核中经常大量使用这种般要避免使用语句在本书中所包含不到40 000行代码中共有 500多条goto语句大约是每 80行个除汇编文件外精确统计数字是接近每72行个goto语句公平地说这是选择偏向结果 : 比例如此高原因的是本书中涉及是内核源核心在这里速度比其他原因都需要优先考虑整个内核比例大
33、概是每 260行个goto语句然而这仍然是我不再使用Basic 进行编程以来见过使用 goto频率最高地方 代码必需受特定编译器限制特性不仅和普通应用开发有很大区别而且也区别于大多数内核开发大多数开发人员使用C语言编写代码来保持较高可移植性即使在编写操作系统时也是如此这样做优点是显而易见最为重要点是旦出现更好编译器员们可以随时进行更换 内核对于 gcc特性完全依赖使得内核向新编译器上移植更加困难最近Linus 对这问题在有关内核邮件列表上表明了自己观点: “记住编译器只是个工具”这是对依赖于gcc特性个很好基本思想表述 : 编译器只是为了完成工作如果通过遵守标准还不能达到工作要求那么就不是工作
34、要求有问题而是对于标准依赖有问题 在大多数情况下这种观点是不能被人所接受通常情况下为了保证和语言标准致开发人员可能需要牺牲某些特性、速度或者其他相关原因其他选择可能会为后期开发造成很大麻烦 但是在这种特定情况下Linus 是正确 Linux 内核是个特例其执行速度要比向其他编译器可移植性远为重要如果设计目标是编写个可移植性好而不要求快速运行内核或者是编写个任何人都可以使用自己喜欢编译器进行编译内核那么结论就可能会有所区别了;而这些恰好不是Linux 设计目标实际上 gcc几乎可以为所有能够运行LinuxCPU 生成代码因此对于gcc依赖并不是可移植性严重障碍 在第3章中我们将对内核设计目标进行
35、详细介绍说明 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 14 页 - - - - - - - - - 2.1.2 内核代码习惯用语 内核代码中使用了些显著习惯用语本节将介绍常用几个当通读源代码时真正重要问题并不在这些习惯用语本身而是这种类型习惯用语确存在而且是不断被使用和发展如果你需要编写内核代码你应该注意到内核中所使用习惯用语并把这些习惯用语应用到你代码中当通读本书( 或者代码 ) 时看看你还能找到多少习惯用语 为了讨论这些习惯用语我们首先需要对它们进行命名为了便
36、于讨论笔者创造了这些名字而在实际中大家不定非要参考这些用语它们只是对内核工作方式描述而已 个普通习惯用语笔者称的为“资源获取”(resource acquisition idiom)在这个用语中个必须实现系列资源获取包括内存、锁等等( 这些资源类型未必相同) 只有成功地获取当前所需要资源的后才能处理后面资源请求最后该还必须释放所有已经获取资源而不必考虑没有获取资源 我采用“变量”这用语 (error variable idiom)来辅助介绍说明资源获取用语它使用个临时变量来记录期望返回值当然相当多都能实现这个功能但是变量区别点在于它通常是用来处理由于速度原因而变得非常复杂流程控制中问题变量有两
37、个典型值0(表示成功 ) 和负数 ( 表示有错 ) 如果执行到标号 out2则都已经获取了 r1和r2资源而且也都需要进行释放如果执行到标号out1( 不管是顺序执行还是使用goto语句进行跳转到 ) 则r2资源是无效( 也可能刚被释放 ) 但是r1资源却是有效而且必需在此将其释放同理如果标号out 能被执行则 r1和r2资源都无效err 所返回是或成功标志 在这个简单例子中对 err 些赋值是没有必要在实战中实际代码必须遵守这种模式这样做原因主要在于同行中可能包含有多种测试而这些测试应该返回相同代码因此对变量统赋值要比多次赋值更为简单虽然在这个例子中对于这种属性必要性并不非常迫切但是我还是倾
38、向于保留这种特点有关实际应用可以参考sys_shmctl( 第21654行) 在第9章中还将详细介绍这个例子 2.1.3 减少#和#def使用 现在Linux 内核已经移植到区别平台上但是我们还必须解决移植过程中所出现问题大部分支持各种区别平台代码由于包含许多预处理代码而已经变得非常不规范标准例如: 这个例子试图实现操作系统可移植性虽然Linux 关注焦点很明显是实现代码在各种 CPU 上可移植性但是 2 者基本原理是致对于这类问题来说预处理器是种解决方式这些杂乱问题使得代码晦涩难懂更为糟糕是增加对新平台支持有可能要求重新遍历这些杂乱分布低质量代码段( 实际上你很难能找到这类代码段全部 ) 和
39、现有方式区别是 Linux 般通过简单 ( 或者是宏 ) 来抽象出区别平台间差异内核移植可以通过实现适合于相应平台 ( 或宏) 来实现这样不仅使代码主体简单易懂而且在移植过程中还可以比较容易地自动检测出你没有注意到内容 : 如引用未声明时会出现链接有时用预处理器来支持区别体系结构但这种方式并不常用而相对于代码风格变化就更是微不足道了 顺便说下我们可以注意到这种解决思路方法和使用用户对象( 或者C语言中充满指针struct 结构) 来代替离散 switch 语句处理区别类型思路方法十分相似在某些层次上这些问题和解决思路方法是统 可移植性问题并不仅限于平台和CPU 移植编译器也是个重要问题此处为了
40、简化假设Linux 只使用 gcc来编译由于Linux 只使用同个编译器所以就没有必要使用#块( 或者#def块) 来选择区别编译器 内核代码主要使用#def来区分需要编译或不需要编译部分从而对区别结构提供支持例如代码经常测试SMP 宏是否定义过从而决定是否支持 SMP 机 2.2 代码样例 了解Linux 代码风格最好思路方法就是实际研究下它部分代码即使你不完全理解本节所讨论代码细节也无关紧要毕竟本节主要目不是理解代码些读者可以只对本节进行浏览本节主要目是让读者对Linux 代码进名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - -
41、 名师精心整理 - - - - - - - 第 6 页,共 14 页 - - - - - - - - - 行初步了解为今后工作提供必要基础该讨论将涉及部分广泛使用内核代码 2.2.1 prk prk(25836行) 是内核内部消息日志记录在出现诸如内核检测到其数据结构出现不致事件时内核会使用prk 把相关信息打印到系统控制台上对于prk 般分为如下几类 : * 紧急事件 (emergency) 例如 panic(25563 行) 多次使用了 prk 当内核检测到发生不可恢复内部时就会 panic 然后尽其所能地安全关闭计算机这个中prk 以提示用户系统将要关闭 * 调试从3816行开始 #de
42、f块使用 prk 来打印 SMP 逻辑单元 (box) 中每个处理器相关配置信息但是此过程只有在使用SMP_DEBUG标志编译代码情况下才能够被执行 * 普通信息例如当机器启动时内核必须估计系统速度以确保设备驱动能够忙等待 (busy-wait)个精确极短周期计算这种估计值名为calibrate_delay(19654行) 它既在19661行使用 prk 声明马上开始计算又在 19693行报告计算结果另外在第4章将详细介绍 calibrate_delay 如果你已经浏览过这些参照行你可能已经注意到prk 和prf 参数十分类似 : 个格式化串后跟零个或者多个参数加入串中格式化串可能是以组“”开
43、始这里N是从0到7数字包括 0和7在内数字区分了消息日志等级(log level)只有当日志等级高于当前控制台定义日志等级(console_loglevel25650行) 时才会打印消息 root 可以通过适当减小控制台日志等级来过滤不是很紧急消息如果内核在格式化串中检测不到日志等级序列那么就会直打印消息( 实际上日志等级序列并不定要在格式化串中出现可以在格式化文本中查找到它代码) 从14946行开始 #块介绍说明了这些特殊序列这些定义可以帮助者正确区分对prk 简单地说我称日志等级 0到4为“紧急事件”等级 5到等级 6为“普通信息”等级 7自然就是我所说“调试”( 这种分类思路方法并不意味
44、着其他更好分类思路方法没有用处而只是目前我们还不关心它而已 ) 在上面讨论基础上我们研究下代码本身 prk 25836:参数fmt 是prf 类型格式化串如果你对“. ”部分内容不熟悉那就 需要参阅本好 C语言参考书 ( 在其索引中查找“变参 variadic function”) 另外在安装 GNU/Linux中stdarg 帮助里也包含了个有关变参简明描述在这儿只需要敲入“man stdarg ”就可以看到 简单地说“ . ”部分提示编译器 fmt 后面可能紧跟着数量不定任何类型参数由于这些参数在编译时候还没有类型和名字内核使用由3个宏va_start 、va_arg和va_end组成特殊
45、组及个特殊类型va_list对它们进行处理 25842:msg_level记录了当前消息日志等级它是静态这看起来可能会有些奇怪为什么下次对prk 需要记录日志等级呢?问题答案是只有打印出新行 (n) 或者赋给个新日志等级序列以后当前消息才会结束这样通过在包含消息结束新行里prk 就保证了在多个短期冲突情况下者只打印唯个长消息 25845: 在SMP 逻辑单元中内核可能试图从区别CPU 向控制台同时打印信息 ( 有时在单处理机 (UP)逻辑单元中也会发生同样问题但由于中断还未被覆盖掉所以问题也并不十分明显) 如果不进行任何协同话结果就将处于完全无法让人了解杂乱无章状态每个消息各个部分都和其他消息
46、各个部分混杂交织在起 相反内核使用旋转锁 (spin-lock)来控制对控制台访问旋转锁将在第10章进行深入介绍 如果你对flags 在传送给 spin_lock_irqsave的前为什么不对它化感到疑惑请不要担心:spin_lock_irqsave(对于区别版本请分别参看 12614行12637行12716行和12837行) 是个宏而不是个该宏实际上是将值写入flags 中而不是从 flags 中读出值 ( 在25895行中在 flags 中信息被 spin_unlock_irqrestore回读请参看 12616行12639行12728行和12841行) 25846:化变量 args该变量
47、代表 prk 参数中“ . ”部分 25848: 内核自身 vsprf( 为节省空间而省略 ) 实现该功能和标准 vsprf 非常相似向 buf 中写入格式化文本 (25634行) 并返回写入串长度 ( 长度不包括最后位终止 0字节) 很快你将可以看到为什么这种机制会忽略buf 前 3 个 ( 正如25847行注释中所述 ) 我们应该注意到在这里并没有名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 7 页,共 14 页 - - - - - - - - - 采取严格措施来保证缓冲器不会
48、过载这里系统假定1024个长度 buf 已经足够使用 ( 参阅25634行) 如果内核在这里能够使用 vsnprf 话情况就会好许多然而 vsnprf 还有另外个参数限制了它能够写入缓冲器长度 25849: 计算buf 中最近使用元素 va_end终止对“ . ”参数处理 25851: 开始格式化消息循环其中存在个内部循环能够处理更多内容( 这点随后就能看到 ) 因此每次内循环开始都开始个新打印行由于通常情况下prk 只用于打印单行所以在每次中这种循环通常只执行次 25853: 如果预先不知道消息日志等级prk 会检查当前行是否以日志等级序列开头25860:如果不是 buf 中开始未使用 3
49、个就能够起作用了 ( 第次以后每次循环都会覆盖部分消息文本但是这样并不会引起问题这里文本只是前面行中部分它们已经被打印过而且以后也不再需要了) 这样就可以将日志等级插入buf 中 25866: 此处有如下属性 :p 指向日志等级序列 ( 消息文本紧随其后 )msg指向消息文本请注意 25852行和25865行中对 msg 赋值 由于已知 p用来指示日志等级序列开头该日志等级序列可能是由自身所创建日志等级可以从 p中抽出并存到 msg_level 中 25868: 没有检测到新行清空 line_feed 标志 25869: 这是前面谈到过内循环循环将运行到本行结束 ( 也就是检测到新行标志 )
50、或者缓冲器末尾为止 25870: 除了将消息打印到控制台的外prk 还能够记录最近打印长度为LOG_ BUF_LEN组(LOG_BUF_LEN为16K请参看 25632行) 如果在控制台打开的前内核就已经prk 则显然不能在控制台上正确打印消息但是这些消息将被尽可能地到 log_buf 中(25656行) 当控制台打开以后缓存 Cache 在log_buf 中数据就可以转储并在控制台上打印出来请参看 25988行 log_buf是个循环缓冲器 log_start和log_size 变量(25657行和25646行) 分别记录当前缓冲器开始位置和长度本行中按位和(AND)操作实际上是快速求模 (