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

📄 00000004.htm

📁 一份很好的linux入门资料
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<HTML><HEAD>  <TITLE>BBS水木清华站∶精华区</TITLE></HEAD><BODY><CENTER><H1>BBS水木清华站∶精华区</H1></CENTER>发信人:&nbsp;axp33a&nbsp;(无聊中...),&nbsp;信区:&nbsp;Linux&nbsp;<BR>标&nbsp;&nbsp;题:&nbsp;Linux内核源代码分析2-2-1&nbsp;<BR>发信站:&nbsp;BBS&nbsp;水木清华站&nbsp;(Thu&nbsp;Aug&nbsp;&nbsp;3&nbsp;11:20:29&nbsp;2000)&nbsp;WWW-POST&nbsp;<BR>&nbsp;<BR>2.2&nbsp;&nbsp;&nbsp;代码样例
&nbsp;<BR>了解Linux代码风格最好的方法就是实际研究一下它的部分代码。即使你不完全理解本节&nbsp;<BR>所讨论代码的细节也无关紧要,毕竟本节的主要目的不是理解代码,一些读者可以只对本&nbsp;<BR>节进行浏览。本节的主要目的是让读者对Linux代码进行初步了解,为今后的工作提供必&nbsp;<BR>要基础。该讨论将涉及部分广泛使用的内核代码。
&nbsp;<BR>2.2.1&nbsp;&nbsp;&nbsp;printk
&nbsp;<BR>printk(25836行)是内核内部消息日志记录函数。在出现诸如内核检测到其数据结构出&nbsp;<BR>现不一致的事件时,内核会使用printk把相关信息打印到系统控制台上。对于printk的调&nbsp;<BR>用一般分为如下几类:
&nbsp;<BR>*&nbsp;紧急事件(emergency)—例如,panic函数(25563行)多次使用了printk。当内核检&nbsp;<BR>测到发生不可恢复的内部错误时就会调用panic函数,然后尽其所能地安全关闭计算机。&nbsp;<BR>这个函数中调用printk以提示用户系统将要关闭。
&nbsp;<BR>*&nbsp;调试—从3816行开始的#ifdef块使用printk来打印SMP逻辑单元(box)中每一个处理器&nbsp;<BR>的相关配置信息,但是此过程只有在使用SMP_DEBUG标志编译代码的情况下才能够被执行&nbsp;<BR>。
&nbsp;<BR>*&nbsp;普通信息—例如,当机器启动时,内核必须估计系统速度以确保设备驱动程序能够忙等&nbsp;<BR>待(busy-wait)一个精确的极短周期。计算这种估计值的函数名为calibrate_delay(&nbsp;<BR>19654行),它既在19661行使用printk声明马上开始计算,又在19693行报告计算结果。&nbsp;<BR>另外,在第4章将详细的介绍calibrate_delay函数。
&nbsp;<BR>如果你已经浏览过这些参照行,你可能已经注意到printk和printf的参数十分类似:一个&nbsp;<BR>格式化字符串,后跟零个或者多个参数加入字符串中。格式化字符串可能是以一组“&lt;N&gt;&nbsp;<BR>”开始,这里的N是从0到7的数字,包括0和7在内。数字区分了消息的日志等级(log&nbsp;&nbsp;<BR>level),只有当日志等级高于当前控制台定义的日志等级(console_loglevel,25650行&nbsp;<BR>)时,才会打印消息。root可以通过适当减小控制台的日志等级来过滤不是很紧急的消息&nbsp;<BR>。如果内核在格式化字符串中检测不到日志等级序列,那么就会一直打印消息(实际上,&nbsp;<BR>日志等级序列并不一定要在格式化字符串中出现,可以在格式化文本中查找到它的代码)&nbsp;<BR>。
&nbsp;<BR>从14946行开始的#define块说明了这些特殊序列,这些定义可以帮助调用者正确区分对&nbsp;<BR>printk的调用。简单地说,我称日志等级0到4为“紧急事件”,等级5到等级6为“普通信&nbsp;<BR>息”,等级7自然就是我所说的“调试”(这种分类方法并不意味着其他更好的分类方法&nbsp;<BR>没有用处,而只是目前我们还不关心它而已)。
&nbsp;<BR>在上面讨论的基础上,我们研究一下代码本身。
&nbsp;<BR>printk
&nbsp;<BR>25836:参数fmt是printf类型的格式化字符串。如果你对“...”部分的内容不熟悉,那&nbsp;<BR>就&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;需要参阅一本好的C语言参考书(在其索引中查找“变参函数,&nbsp;<BR>variadic&nbsp;function”)。另外,在安装的GNU/Linux中的stdarg帮助里也包含了一个有关&nbsp;<BR>变参函数的简明描述,在这儿只需要敲入“man&nbsp;stdarg”就可以看到。
&nbsp;<BR>简单地说,“...”部分提示编译器fmt后面可能紧跟着数量不定的任何类型的参数。由于&nbsp;<BR>这些参数在编译的时候还没有类型和名字,内核使用由三个宏va_start、va_arg和va_end&nbsp;<BR>组成的特殊组及一个特殊类型—va_list对它们进行处理。
&nbsp;<BR>25842:msg_level记录了当前消息的日志等级。它是静态的,这看起来可能会有些奇怪—&nbsp;<BR>为什么下一次对printk的调用需要记录日志等级呢?问题的答案是只有打印出新行(\n)&nbsp;<BR>或者赋给一个新的日志等级序列以后,当前消息才会结束。这样,通过在包含消息结束的&nbsp;<BR>新行里调用printk,就保证了在多个短期冲突的情况下,调用者只打印唯一一个长消息。&nbsp;<BR>
&nbsp;<BR>25845:在SMP逻辑单元中,内核可能试图从不同的CPU向控制台同时打印信息(有时在单&nbsp;<BR>处理机(UP)逻辑单元中也会发生同样问题,但由于中断还未被覆盖掉,所以问题也并不&nbsp;<BR>十分明显)。如果不进行任何协同的话,结果就将处于完全无法让人了解的杂乱无章的状&nbsp;<BR>态,每个消息的各个部分都和其他消息的各个部分混杂交织在一起。
&nbsp;<BR>相反,内核使用旋转锁(spin-lock)来控制对控制台的访问。旋转锁将在第10章进行深&nbsp;<BR>入介绍。
&nbsp;<BR>如果你对flags&nbsp;在传送给spin_lock_irqsave之前为什么不对它初始化感到疑惑,请不要&nbsp;<BR>担心:spin_lock_irqsave(对于不同的版本请分别参看12614行,12637行,12716行和&nbsp;<BR>12837行)是一个宏,而不是一个函数。该宏实际上是将值写入flags中,而不是从flags&nbsp;<BR>中读出值(在25895行中,存储在flags中的信息被spin_unlock_irqrestore回读,请参看&nbsp;<BR>12616行,12639行,12728行和12841行)。
&nbsp;<BR>25846:初始化变量args,该变量代表printk参数中的“...”部分。
&nbsp;<BR>25848:调用内核自身的vsprintf(为节省空间而省略)实现。该函数的功能与标准&nbsp;<BR>vsprintf函数非常相似,向buf中写入格式化文本(25634行)并返回写入字符串的长度(&nbsp;<BR>长度不包括最后一位终止字符0字节)。很快,你将可以看到为什么这种机制会忽略buf的&nbsp;<BR>前三个字符。
&nbsp;<BR>(正如25847行的注释中所述)我们应该注意到在这里并没有采取严格的措施来保证缓冲&nbsp;<BR>器不会过载。这里系统假定1024个字符长度的buf已经足够使用(参阅25634行)。如果内&nbsp;<BR>核在这里能够使用vsnprintf函数的话,情况就会好许多。然而,vsnprintf还有另外一个&nbsp;<BR>参数限制了它能够写入缓冲器的字符长度。
&nbsp;<BR>25849:计算buf中最近使用的元素,调用va_end终止对“...”参数的处理。
&nbsp;<BR>25851:开始格式化消息的循环。其中存在一个内部循环能够处理更多内容(这一点随后&nbsp;<BR>就能看到),因此,每次内循环开始,都开始一个新的打印行。由于通常情况下printk只&nbsp;<BR>用于打印单行,所以在每次调用中,这种循环通常只执行一次。
&nbsp;<BR>25853:如果预先不知道消息的日志等级,printk会检查当前行是否以日志等级序列开头&nbsp;<BR>。
&nbsp;<BR>25860:如果不是,buf中开始未使用的三个字符就能够起作用了(第一次以后的每次循环&nbsp;<BR>,都会覆盖部分消息文本,但是这样并不会引起问题,因为这里的文本只是前面行中的一&nbsp;<BR>

⌨️ 快捷键说明

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