我正在Ubuntu 4.14.12上制作Linux内核模块。
我对printk()的理解是,保证可以在运行下一行代码之前立即将其输出到控制台,而不是将其输出放置在最终在某个时候刷新的缓冲区上。它是否正确?
多次printk调用后发生了几百行崩溃,该崩溃的输出没有使用-wH命令在dmesg中出现,或者在通过tee发送到重新启动后读取的文件的dmesg中没有出现。
在将printk发送到控制台的时间与在dmesg中显示的时间之间是否存在滞后,这将使我的系统在看到输出之前冻结起来?还是还有其他事情发生?
dmesg在修复有问题的代码行后显示了有问题的printks。控制台日志级别设置为高于所讨论的printks的控制台日志级别。
最佳答案
模块调用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
函数后面的汇编指令,然后将所有层向上放置,直到将它们置于__log_buf静态中为止变量。然后我在console_unlock内部某个地方唤醒了正在等待dmesg
syscall的read()
。唤醒后,dmesg
将最终调用devkmsg_read()函数,该函数将返回缓冲区。然后dmesg()
将在收到数据后在stdout上调用write()
syscall。然后write()
内核syscall将尝试在屏幕上写入内容-因此数据必须一直通过控制台驱动程序以及显示驱动程序和图形驱动程序。总是有滞后的。但这应该是最小的。
dmesg在修复有问题的代码行后显示了有问题的printks
只是说dmesg
没有从内核日志获取输出。可能还有其他情况发生。最简单的是dmesg
进程无法获取cpu时间,在读取syslog时被阻塞,模块在禁用irq的情况下在内部执行,依此类推。
关于c - 是什么使printk无法立即在dmesg中显示?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55093424/