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

📄 00000004.htm

📁 一份很好的linux入门资料
💻 HTM
📖 第 1 页 / 共 2 页
字号:
部分,它们已经被打印过,而且以后也不再需要了)。这样,就可以将日志等级插入buf&nbsp;<BR>中。
&nbsp;<BR>25866:此处有如下属性:p指向日志等级序列(消息文本紧随其后),msg指向消息文本&nbsp;<BR>—请注意25852行和25865行中对msg的赋值。
&nbsp;<BR>由于已知p用来指示日志等级序列的开头—该日志等级序列可能是由函数自身所创建的,&nbsp;<BR>日志等级可以从p中抽出并存到msg_level中。
&nbsp;<BR>25868:没有检测到新行,清空line_feed标志。
&nbsp;<BR>25869:这是前面谈到过的内循环,循环将运行到本行结束(也就是检测到新行标志)或&nbsp;<BR>者缓冲器的末尾为止。
&nbsp;<BR>25870:除了将消息打印到控制台之外,printk还能够记录最近打印的长度为LOG_&nbsp;&nbsp;<BR>BUF_LEN的字符组(LOG_BUF_LEN为16K,请参看25632行)。如果在控制台打开之前,内核&nbsp;<BR>就已经调用printk,则显然不能在控制台上正确打印消息,但是这些消息将被尽可能地存&nbsp;<BR>储到log_buf中(25656行)。当控制台打开以后,缓存在log_buf中的数据就可以转储并&nbsp;<BR>在控制台上打印出来,请参看25988行。
&nbsp;<BR>log_buf是一个循环缓冲器,log_start和log_size变量(25657行和25646行)分别记录当&nbsp;<BR>前缓冲器的开始位置和长度。本行中的按位与(AND)操作实际上是快速求模(%)运算&nbsp;<BR>,它的正确性依赖于LOG_BUF_LEN的值是2的幂。
&nbsp;<BR>25872:保存变量跟踪记录循环日志的值。显然,日志大小会不断增长,直至达到&nbsp;<BR>LOG_BUF_LEN的值为止。此后,log_size将保持不变,而插入新字符将导致log_start的增&nbsp;<BR>长。
&nbsp;<BR>25878:请注意logged_chars(25658行)记录从机器启动之后由printk写入的所有字符的&nbsp;<BR>长度,它在每次循环中都会被更新,而不是在循环结束后才改变一次。基于同样的道理,&nbsp;<BR>log_start和log_size的处理方式也是一样。这实际上是一种优化的时机,本书将在结束&nbsp;<BR>对函数的介绍之后再对它进行详细讨论。
&nbsp;<BR>25879:消息被分为若干行,这当然要使用新行标志符来进行分割。一旦内核检测到新行&nbsp;<BR>标志符,就写入一个完整行,从而内循环的执行也可以提前终止。
&nbsp;<BR>25884:在这里我们先不考虑内部循环是否会提前退出,从msg到p的字符序列是专门提供&nbsp;<BR>给控制台使用的(这种字符序列我称之为行,但是不要忘了,这里的行可能并不意味着新&nbsp;<BR>行终止,因为buf也许还没有终止)。如果该行的日志等级高于系统控制台定义的日志等&nbsp;<BR>级,而且当前又有控制台可供打印,那么就能够正确打印该行。(记住,printk可能在所&nbsp;<BR>有控制台打开之前就已经被调用过了。)
&nbsp;<BR>如果在该消息块中没有发现日志等级序列,并且在前面的printk调用中也没有对&nbsp;<BR>msg_level赋值,那么本行中的msg_level就是-1。由于console_loglevel总不小于1(除&nbsp;<BR>非root通过sysctl接口锁定),于是总是可以打印这些行。
&nbsp;<BR>25886:本行应该能够被打印。printk通过遍历打开的控制台驱动链表告知每一个控制台&nbsp;<BR>驱动去打印当前行设备驱动在本书的讨论范围之外,因此,控制台驱动代码则并不包含在&nbsp;<BR>内)。
&nbsp;<BR>25888:请注意这里消息文本的开头使用的是msg而不是p,这样就在没有日志等级序列的&nbsp;<BR>情况下写入消息了。然而,日志等级序列已经被存储到log_buf缓冲器中了。这样就使后&nbsp;<BR>来能够访问log_buf以获取消息日志等级的代码(请参看25998行),不会再产生显示混乱&nbsp;<BR>信息序列的现象。
&nbsp;<BR>25892:如果内层for循环发现一新行,那么buf中的剩余字符(如果有的话)将被认为是&nbsp;<BR>新的消息,因此msg_level会被重置。但是无论怎样,外层循环都会持续到buf清空为止。&nbsp;<BR>
&nbsp;<BR>25895:释放在25845行获取的控制台锁(console&nbsp;lock)。
&nbsp;<BR>25896:唤醒等待被写入控制台日志的所有进程。注意即使没有文本被实际写入任何控制&nbsp;<BR>台,这个过程也仍然会发生。这样处理是正确的,因为无论是否要往控制台中写入文本,&nbsp;<BR>等待进程实际上都是在等待从log_buf中读出信息。在25748行,进程被转入休眠状态以等&nbsp;<BR>待log_buf的活动。在休眠、唤醒和等待队列中所使用的机制将在下一节中进行讨论。
&nbsp;<BR>25897:返回日志中写入的字符长度。
&nbsp;<BR>如果对于每个字符的处理工作都能减少一点,那么从25869行开始的for循环就执行得更快&nbsp;<BR>一点。当循环存在时,我们可以通过只在循环退出时将logged_chars更新一次来稍微提高&nbsp;<BR>运行速度。然而我们还可以通过其他努力来提高速度。由于我们可以预知消息的长度,因&nbsp;<BR>此log_size和log_start可以到最后再增长。让我们来实验一下这样能否提高速度,下面&nbsp;<BR>是一段经过理想优化的代码:
&nbsp;<BR>请注意循环通常只需要执行一次,只有在log_buf末尾写入信息需要折行时才会多次执行&nbsp;<BR>。因而log_size和log_buf只需要更新一次(或者当写入需要换行时是两次)。
&nbsp;<BR>这时速度的确提高了,但是有两个原因使我们并不能这样做。首先,内核可能有自己特有&nbsp;<BR>的memcpy函数,我们必须确保对memcpy的调用不会再次进入对printk的调用(有一部分内&nbsp;<BR>核移植版定义了自己特有的速度较快的memcpy函数版本,因此所有的移植都要在这一点上&nbsp;<BR>保持一致)。如果memecpy调用printk来报告失败,那么就有可能触发无限循环。
&nbsp;<BR>然而在这一点上也并不是真的无药可救。使用这种解决方案的最大问题在于该内核循环的&nbsp;<BR>形式中也要留意新行标志符,因此使用memcpy将整个消息拷贝到log_buf中是不正确的:&nbsp;<BR>如果此处存在新行,我们将无法对其进行处理。
&nbsp;<BR>我们可以试验一个一箭双雕的办法。下面这种替代的尝试虽然可能比前面那种初步解决方&nbsp;<BR>法速度要慢,但是它保持了内核版本的语意:
&nbsp;<BR>(请注意gcc的优化器十分灵敏,它足以能检测到循环内部的表达式log_buf+LOG_BUF_LEN&nbsp;<BR>并没有改变,因此在上面的循环中试图手工加速计算是没有任何效果的。)
&nbsp;<BR>不幸的是,这种方法并不能比现在的内核版本在速度上快许多,而且那样会使得代码晦涩&nbsp;<BR>难懂(如果你编写过更新log_size和log_start的代码,你就能清楚地了解这一点)。你&nbsp;<BR>可以自己决定这种折衷是否值得。然而无论怎样,我们学到了一些东西,通常,不管成功&nbsp;<BR>与否,改进内核代码都可以加深你对内核工作原理的理解。
&nbsp;<BR>
&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>--&nbsp;<BR>※&nbsp;来源:·BBS&nbsp;水木清华站&nbsp;smth.org·[FROM:&nbsp;166.111.196.22]&nbsp;&nbsp;<BR><CENTER><H1>BBS水木清华站∶精华区</H1></CENTER></BODY></HTML>

⌨️ 快捷键说明

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