1. 概述

printk 用于在终端上打印内核想要输出的信息,平常我们较多使用的打印函数是 printf,两者名字虽然只有最后一个字母不同,且都是为了在终端上显示信息,但是它们的应用场景并不相同。printk 是 linux 内核用来打印消息的,而 printf 则是用户态模式下打印消息用的,不过最终 printf 会通过系统调用的方式使用 printk 进行消息的显示。printk 的整体代码流程如下:

2. 代码分析

首先是 printk 函数,因为 printk 函数是支持不定参数的,所以第一步就是先解析参数,之后就是调用 vprintk 函数了。

asmlinkage int printk(const char *fmt, ...)
{
... 省略 ...
va_start(args, fmt);
r = vprintk(fmt, args);
va_end(args); return r;
}

对于 vprintk 函数,其主要步骤如上图所示,首先是调用 vscnprintf 格式化字符串,并放入到 printk_buf 中,接下来就是再根据 log level 以及是否需要增加时间前缀等信息再次格式化字符串,并将最后的字符串从 printk_buf 复制到 log_buff 中,最后就是将 log_buff 中的字符串输出到终端上,实际执行输出操作的是在 console_unlock() 中进行的。

asmlinkage int vprintk(const char *fmt, va_list args)
{
... 简略版 ...
raw_spin_lock(&logbuf_lock);
/* 格式化到 printk_buf */
printed_len += vscnprintf(printk_buf + printed_len,
sizeof(printk_buf) - printed_len, fmt, args);
/* 格式化到 log_buf */
for (; *p; p++) {
if (new_text_line) {
new_text_line = 0;
...
} emit_log_char(*p);
if (*p == '\n')
new_text_line = 1;
}
/* 将 log_buf 中的字符串输出到终端上*/
if (console_trylock_for_printk(this_cpu))
console_unlock(); return printed_len;
}

在 console_unlock 中,首先根据 con_start 和 log_end 来检查是否有需要在终端上打印的消息,如果有则开始使用 call_console_drivers 调用 console 关联的底层驱动程序进行最终的消息打印操作。

void console_unlock(void)
{
...
again:
for ( ; ; ) {
raw_spin_lock_irqsave(&logbuf_lock, flags);
wake_klogd |= log_start - log_end;
if (con_start == log_end)
break;
_con_start = con_start;
_log_end = log_end;
con_start = log_end;
raw_spin_unlock(&logbuf_lock);
stop_critical_timings();
call_console_drivers(_con_start, _log_end);
start_critical_timings();
local_irq_restore(flags);
}
console_locked = 0;
...
}

而 call_console_drivers 函数又调用了 _call_console_drivers,进一步调用 __call_console_drivers,最终调用不同 console 关联的写操作 con->write(con, &LOG_BUF(start), end - start) 实现打印操作。

static void __call_console_drivers(unsigned start, unsigned end)
{
struct console *con; for_each_console(con) {
if (exclusive_console && con != exclusive_console)
continue;
if ((con->flags & CON_ENABLED) && con->write &&
(cpu_online(smp_processor_id()) ||
(con->flags & CON_ANYTIME)))
con->write(con, &LOG_BUF(start), end - start);
}
}

3. 总结

  • printk 函数第一步是解析参数列表,然后对带有参数的字符串进行格式化,并放入到 printk_buf 中,最后再根据 log level 以及是否需要加时间前缀等配置再次格式化字符串,并放入到 log_buf 中;

  • 当 log_buf 中有需要打印的信息时,则调用 console 所关联的驱动程序完成最终的打印操作。

  • 在 __call_console_drivers 中调用 console 所关联的驱动时会先判断 con->write 是否存在,如果 con->write 不存在,则不会在终端中有信息输出,即直接忽略这次打印,然而在 linux 内核启动初期就已经开始调用 printk 函数了,而此时还并没注册 console 设备,就更不可能存在 con->write 了,那这个阶段调用 printk 输出的信息岂不是都丢了?然而事实并不是这样子的,欲知后事如何,且听下回分解。

printk 流程分析的更多相关文章

  1. S3C6410 SPI全双工读写流程分析(原创)【转】

    转自:http://blog.csdn.net/hustyangju/article/details/21165721 原创博文,知识共享!转载请注明出处:http://blog.csdn.net/h ...

  2. 基于linux与busybox的reboot命令流程分析

    http://www.xuebuyuan.com/736763.html 基于Linux与Busybox的Reboot命令流程分析 ********************************** ...

  3. 8、Struts2 运行流程分析

    1.流程分析: 请求发送给 StrutsPrepareAndExecuteFilter StrutsPrepareAndExecuteFilter 询问 ActionMapper: 该请求是否是一个 ...

  4. freeswitch呼叫流程分析

    今天翻文档时发现之前整理的关于freeswitch呼叫相关的内容,写成博文分享出来也方便我以后查阅. 整体结构图 FreeswitchCore 模块加载过程 freeswitch主程序初始化时会从mo ...

  5. u-boot 流程分析

    u-boot 介绍: 对于计算机来说 , 从一开始上机通电是无法直接启动操作系统的 , 这中间需要一个引导过程 , 嵌入式Linux系统同样离不开引导程序 ,  这个启动程序就叫启动加载程序(Boot ...

  6. thttpd和cgilua安装与运行流程分析

    安装 参考如下博文安装thttpd软件 http://blog.csdn.net/21aspnet/article/details/7045845 http://blog.csdn.net/drago ...

  7. 【转】Hostapd工作流程分析

    [转]Hostapd工作流程分析 转自:http://blog.chinaunix.net/uid-30081165-id-5290531.html Hostapd是一个运行在用户态的守护进程,可以通 ...

  8. u-boot中nandflash初始化流程分析(转)

    u-boot中nandflash初始化流程分析(转) 原文地址http://zhuairlunjj.blog.163.com/blog/static/80050945201092011249136/ ...

  9. Android7.0 Phone应用源码分析(二) phone来电流程分析

    接上篇博文:Android7.0 Phone应用源码分析(一) phone拨号流程分析 今天我们再来分析下Android7.0 的phone的来电流程 1.1TelephonyFramework 当有 ...

随机推荐

  1. 安装Ubuntu虚拟机

    centos已经满足不了我了,这里就装了个虚拟机,等有钱了再单配台单系统的Linux主机. 一.下载Ubuntu的ISO文件 用国内的网易镜像站点 进去点个16.04.6,然后下个64位的.iso就好 ...

  2. spark 笔记2

    一.Spark Shuffle 的发展 Spark 0.8及以前 Hash Based Shuffle Spark 0.8.1 为Hash Based Shuffle引入File Consolidat ...

  3. Arduino 寻找I2C地址address

    参考:http://henrysbench.capnfatz.com/henrys-bench/arduino-projects-tips-and-more/arduino-quick-tip-fin ...

  4. MyEclipse 设置打开 jsp 文件的默认编辑器

    MyEclipse 版本信息 MyEclipse Enterprise Workbench Version: 2014 Build id: 12.0.0-20131202 菜单 Window > ...

  5. 解决FAT32格式U盘安装Windows 10时的报错(错误代码:0x8007000D)

    一.现象描述 使用UltraISO软碟通将 Windows 10 version 1909 刻录到U盘内来安装系统. 从U盘启动安装过程中,报错如下: "Windows 无法打开所需的文件 ...

  6. 2017-01-26--编译Linux内核2.6.30版本报错解决

    错误一: LD .tmp_vmlinux1 init/built-in.o: In function `run_init_process': /home/ox/tq2440/opt/EmbedSky/ ...

  7. 实验二 HTML中图片和超链接的应用

    实验二 HTML中图片和超链接的应用 [实验目的] 1.通过本例要求掌握常见的图像格式及图像的插入方法. 2.能够修改图像属性,利用外部图像处理软件编辑图像. 3.掌握设置各类超级连接的方法. 4.灵 ...

  8. CSS字体属性与文本属性

    CSS字体属性与文本属性 1. 字体属性 1.1 字体系列font-family p { font-family: "Microsoft Yahei";/*微软雅黑*/ } /*当 ...

  9. MeteoInfoLab脚本示例:读取文本文件

    此例中的降水文本文件下载自"中国气象科学数据共享服务网"(http://cdc.nmic.cn/sksj.do?method=ssrjscp),其实是ESRI的文本格点数据格式.对 ...

  10. 联赛模拟测试18 A. 施工 单调队列(栈)优化DP

    题目描述 分析 对于 \(Subtask\ 1\),可以写一个 \(n^3\) 的 \(DP\),\(f[i][j]\) 代表第 \(i\) 个建筑高度为 \(j\) 时的最小花费,随便转移即可 时间 ...