⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 4.htm

📁 Linux内核源代码分析(水木清华
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>CTerm非常精华下载</title>
</head>
<body bgcolor="#FFFFFF">
<table border="0" width="100%" cellspacing="0" cellpadding="0" height="577">
<tr><td width="32%" rowspan="3" height="123"><img src="DDl_back.jpg" width="300" height="129" alt="DDl_back.jpg"></td><td width="30%" background="DDl_back2.jpg" height="35"><p align="center"><a href="http://bbs.tsinghua.edu.cn"><font face="黑体"><big><big>水木清华★</big></big></font></a></td></tr>
<tr>
<td width="68%" background="DDl_back2.jpg" height="44"><big><big><font face="黑体"><p align="center">               内核源代码分析                        (BM: suzhe)                </font></big></big></td></tr>
<tr>
<td width="68%" height="44" bgcolor="#000000"><font face="黑体"><big><big><p   align="center"></big></big><a href="http://cterm.163.net"><img src="banner.gif" width="400" height="60" alt="banner.gif"border="0"></a></font></td>
</tr>
<tr><td width="100%" colspan="2" height="100" align="center" valign="top"><br><p align="center">[<a href="index.htm">回到开始</a>][<a href="index.htm">上一层</a>][<a href="5.htm">下一篇</a>]
<hr><p align="left"><small>发信人: axp33a (无聊中...), 信区: Linux <br>

标  题: Linux内核源代码分析2-2-1 <br>

发信站: BBS 水木清华站 (Thu Aug  3 11:20:29 2000) WWW-POST <br>

  <br>

2.2   代码样例 <br>

了解Linux代码风格最好的方法就是实际研究一下它的部分代码。即使你不完全理解本节 <br>

所讨论代码的细节也无关紧要,毕竟本节的主要目的不是理解代码,一些读者可以只对本 <br>

节进行浏览。本节的主要目的是让读者对Linux代码进行初步了解,为今后的工作提供必 <br>

要基础。该讨论将涉及部分广泛使用的内核代码。 <br>

2.2.1   printk <br>

printk(25836行)是内核内部消息日志记录函数。在出现诸如内核检测到其数据结构出 <br>

现不一致的事件时,内核会使用printk把相关信息打印到系统控制台上。对于printk的调 <br>

用一般分为如下几类: <br>

* 紧急事件(emergency)—例如,panic函数(25563行)多次使用了printk。当内核检 <br>

测到发生不可恢复的内部错误时就会调用panic函数,然后尽其所能地安全关闭计算机。 <br>

这个函数中调用printk以提示用户系统将要关闭。 <br>

* 调试—从3816行开始的#ifdef块使用printk来打印SMP逻辑单元(box)中每一个处理器 <br>

的相关配置信息,但是此过程只有在使用SMP_DEBUG标志编译代码的情况下才能够被执行 <br>

。 <br>

* 普通信息—例如,当机器启动时,内核必须估计系统速度以确保设备驱动程序能够忙等 <br>

待(busy-wait)一个精确的极短周期。计算这种估计值的函数名为calibrate_delay( <br>

19654行),它既在19661行使用printk声明马上开始计算,又在19693行报告计算结果。 <br>

另外,在第4章将详细的介绍calibrate_delay函数。 <br>



如果你已经浏览过这些参照行,你可能已经注意到printk和printf的参数十分类似:一个 <br>

格式化字符串,后跟零个或者多个参数加入字符串中。格式化字符串可能是以一组“<N> <br>

”开始,这里的N是从0到7的数字,包括0和7在内。数字区分了消息的日志等级(log <br>

level),只有当日志等级高于当前控制台定义的日志等级(console_loglevel,25650行 <br>

)时,才会打印消息。root可以通过适当减小控制台的日志等级来过滤不是很紧急的消息 <br>

。如果内核在格式化字符串中检测不到日志等级序列,那么就会一直打印消息(实际上, <br>

日志等级序列并不一定要在格式化字符串中出现,可以在格式化文本中查找到它的代码) <br>

。 <br>

从14946行开始的#define块说明了这些特殊序列,这些定义可以帮助调用者正确区分对 <br>

printk的调用。简单地说,我称日志等级0到4为“紧急事件”,等级5到等级6为“普通信 <br>

息”,等级7自然就是我所说的“调试”(这种分类方法并不意味着其他更好的分类方法 <br>

没有用处,而只是目前我们还不关心它而已)。 <br>

在上面讨论的基础上,我们研究一下代码本身。 <br>

printk <br>

25836:参数fmt是printf类型的格式化字符串。如果你对“...”部分的内容不熟悉,那 <br>

就             需要参阅一本好的C语言参考书(在其索引中查找“变参函数, <br>

variadic function”)。另外,在安装的GNU/Linux中的stdarg帮助里也包含了一个有关 <br>

变参函数的简明描述,在这儿只需要敲入“man stdarg”就可以看到。 <br>

简单地说,“...”部分提示编译器fmt后面可能紧跟着数量不定的任何类型的参数。由于 <br>

这些参数在编译的时候还没有类型和名字,内核使用由三个宏va_start、va_arg和va_end <br>

组成的特殊组及一个特殊类型—va_list对它们进行处理。 <br>

25842:msg_level记录了当前消息的日志等级。它是静态的,这看起来可能会有些奇怪— <br>



为什么下一次对printk的调用需要记录日志等级呢?问题的答案是只有打印出新行(\n) <br>

或者赋给一个新的日志等级序列以后,当前消息才会结束。这样,通过在包含消息结束的 <br>

新行里调用printk,就保证了在多个短期冲突的情况下,调用者只打印唯一一个长消息。 <br>

  <br>

25845:在SMP逻辑单元中,内核可能试图从不同的CPU向控制台同时打印信息(有时在单 <br>

处理机(UP)逻辑单元中也会发生同样问题,但由于中断还未被覆盖掉,所以问题也并不 <br>

十分明显)。如果不进行任何协同的话,结果就将处于完全无法让人了解的杂乱无章的状 <br>

态,每个消息的各个部分都和其他消息的各个部分混杂交织在一起。 <br>

相反,内核使用旋转锁(spin-lock)来控制对控制台的访问。旋转锁将在第10章进行深 <br>

入介绍。 <br>

如果你对flags 在传送给spin_lock_irqsave之前为什么不对它初始化感到疑惑,请不要 <br>

担心:spin_lock_irqsave(对于不同的版本请分别参看12614行,12637行,12716行和 <br>

12837行)是一个宏,而不是一个函数。该宏实际上是将值写入flags中,而不是从flags <br>

中读出值(在25895行中,存储在flags中的信息被spin_unlock_irqrestore回读,请参看 <br>

12616行,12639行,12728行和12841行)。 <br>

25846:初始化变量args,该变量代表printk参数中的“...”部分。 <br>

25848:调用内核自身的vsprintf(为节省空间而省略)实现。该函数的功能与标准 <br>

vsprintf函数非常相似,向buf中写入格式化文本(25634行)并返回写入字符串的长度( <br>

长度不包括最后一位终止字符0字节)。很快,你将可以看到为什么这种机制会忽略buf的 <br>

前三个字符。 <br>

(正如25847行的注释中所述)我们应该注意到在这里并没有采取严格的措施来保证缓冲 <br>

器不会过载。这里系统假定1024个字符长度的buf已经足够使用(参阅25634行)。如果内 <br>



核在这里能够使用vsnprintf函数的话,情况就会好许多。然而,vsnprintf还有另外一个 <br>

参数限制了它能够写入缓冲器的字符长度。 <br>

25849:计算buf中最近使用的元素,调用va_end终止对“...”参数的处理。 <br>

25851:开始格式化消息的循环。其中存在一个内部循环能够处理更多内容(这一点随后 <br>

就能看到),因此,每次内循环开始,都开始一个新的打印行。由于通常情况下printk只 <br>

用于打印单行,所以在每次调用中,这种循环通常只执行一次。 <br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -