内核的() 函数似乎应该相对简单一些。它所做的只是格式化字符串并将其输出到内核日志。但是,这种简单性掩盖了很多潜在的复杂性,而这种复杂性就是为什么内核开发人员在28年后仍然对()不满意的原因。在2019年Linux 大会上,John 解释 了()的复杂性来自何处以及如何改善这种情况。
核心问题:
核心问题始于内核代码必须能够从任何上下文调用()的事实。
换句话说,()看起来很简单,而且绝对无处不在,但是必须将其深深地连接到系统中。
()的历史进化
因此,多年来,()取得了很大的发展,但是仍然存在许多未解决的问题。其中之一是用于保护环形缓冲区的原始自旋锁。它不能在NMI上下文中使用,因此 ()必须输出到无锁安全缓冲区。当消息最终被复制到真实的环形缓冲区时,这将产生虚假的时间戳,可能会丢失消息,并导致在CPU无法正常脱机时不刷新缓冲区。
然后,出现了控制台驱动程序的问题,这些驱动程序很慢,但是在禁用中断的情况下仍被调用。大多数控制台设备并非设计用于在内核崩溃的情况下,因此在最需要它们时它们并不可靠。
其他问题包括()平等对待所有日志级别的事实 ;已经解决了一个CPU永远卡住日志的问题,但是最后一个要接管并接管日志输出的CPU仍然要承担很多工作。这会使任何()调用潜在地变得昂贵。()机制就是“忽略锁并希望达到最佳”。
更好的方法
说,多年来() 的困难归结为无干扰和可靠性之间的平衡关系。试图在同一个地方实现两个目标已被证明是行不通的,所以更好的方法是将它们分开。通过使()完全可抢占,使环形缓冲区在所有上下文中均安全并将控制台处理移至专用内核线程,可以解决无干扰问题。相反,可以通过为重要消息提供同步通道,“原子控制台”概念以及“紧急消息”的概念来实现可靠性。
这两个目标都取决于()环形缓冲区的支持。这个缓冲区有多个并发的读取器和一个写入器。它连续存储在内存中,并受到特殊的自旋锁(“ CPU锁”)的保护,该自旋锁可以在同一CPU上多次获取。他说,这种锁很像旧的大内核锁。
像任何内核开发项目一样,()的 工作从创建新的环形缓冲区开始,该缓冲区旨在解决当前缓冲区的问题。它是完全无锁的,可在所有情况下支持多个读取器和写入器。元数据已推出到单独的描述符机制中;它处理诸如时间戳和排序之类的任务。环形缓冲区具有一些不错的功能,但也很复杂,包括不少于九个内存屏障对。难以记录,难以审查。
每个控制台内核线程的添加用于将 ()调用与控制台处理分离。每个控制台现在将尽可能快地运行,并且每个控制台都有自己的日志级别。转移控制台的职责可以简化很多事情,但会导致一些尚未解决的问题,如锁定以及是否可以依赖基于线程的实现来始终获取消息。
为了可靠性,计划是添加“原子控制台”概念。具有此支持的控制台将具有()方法,可以在任何上下文中使用该方法。该方法被定义为同步运行,这意味着它将大大降低系统速度。因此,它仅用于紧急消息。优点是不再需要()或全局 变量。
———END———
限 时 特 惠: 本站每日持续更新海量各大内部创业教程,永久会员只需109元,全站资源免费下载 点击查看详情
站 长 微 信: nanadh666