我正在Ubuntu 4.14.12上制作Linux内核模块。
我对printk()的理解是,保证可以在运行下一行代码之前立即将其输出到控制台,而不是将其输出放置在最终在某个时候刷新的缓冲区上。这是正确的吗?
我遇到了一个崩溃,它发生在多个printk调用之后的几百行中,这些调用的输出没有出现在使用-wH命令的dmesg中,或者在通过tee发送到重新启动后读取的文件的dmesg中。
在将printk发送到控制台与它在dmesg中显示之间是否存在滞后,这将使我的系统在看到输出之前冻结起来?还是还有其他事情发生?
dmesg在修复有问题的代码行后显示了有问题的printks。控制台日志级别设置为高于所讨论的printks的控制台日志级别。
答案 0 :(得分:0)
模块调用printk(...)
和控制台上显示的输出之间有很多层。
我对printk()的理解是,保证可以在运行下一行代码之前立即将其输出到控制台,而不是将其输出放置在最终在某个时候刷新的缓冲区上。这是正确的吗?
否,这是不正确的。 printk()
实现中没有“控制台”,也不应有任何控制台。总有一个缓冲区,缓冲区的许多层。第1705 in printk.c行回答了您的问题。 printk_emit()
函数使用静态分配的缓冲区static char textbuf[LOG_LINE_MAX];
并对其调用vscnprintf(textbuf, sizeof(textbuf), ...)
来解析参数。因此它使用一个缓冲区。我认为不使用内部缓冲区就不可能编写printf
函数,至少很难。 __log_buf
变量是一个静态分配的缓冲区,是一个字符数组,它是内核日志缓冲区。
在将printk发送到控制台到它在dmesg中显示之间是否存在滞后时间,从而使我的系统在看到输出之前就冻结了?
是吗?总是有滞后的。我不知道如何定义“滞后”(一毫秒?一秒?一纳秒?),但是必须执行printk
函数后面的汇编指令,然后将所有层向上放置,直到将它们放置在{{ 3}}静态变量。然后,dmesg
等待read()
的系统调用被唤醒了,我想是__log_buf内部的某个地方。唤醒之后,dmesg
将最终调用console_unlock函数,该函数将返回缓冲区。然后dmesg()
将在收到数据后在stdout上调用write()
syscall。然后write()
内核syscall将尝试在屏幕上写入内容-因此数据必须一直通过控制台驱动程序以及显示驱动程序和图形驱动程序。总是有滞后的。但这应该是最小的。
dmesg在修复有问题的代码行后显示了有问题的printks
这只是说dmesg
没有从内核日志中获得输出。可能还有其他情况发生。最简单的是dmesg
进程无法获得CPU时间,在读取系统日志时被阻塞,模块在禁用irq的情况下在内部执行,依此类推。