printk 流程分析
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 流程分析的更多相关文章
- S3C6410 SPI全双工读写流程分析(原创)【转】
转自:http://blog.csdn.net/hustyangju/article/details/21165721 原创博文,知识共享!转载请注明出处:http://blog.csdn.net/h ...
- 基于linux与busybox的reboot命令流程分析
http://www.xuebuyuan.com/736763.html 基于Linux与Busybox的Reboot命令流程分析 ********************************** ...
- 8、Struts2 运行流程分析
1.流程分析: 请求发送给 StrutsPrepareAndExecuteFilter StrutsPrepareAndExecuteFilter 询问 ActionMapper: 该请求是否是一个 ...
- freeswitch呼叫流程分析
今天翻文档时发现之前整理的关于freeswitch呼叫相关的内容,写成博文分享出来也方便我以后查阅. 整体结构图 FreeswitchCore 模块加载过程 freeswitch主程序初始化时会从mo ...
- u-boot 流程分析
u-boot 介绍: 对于计算机来说 , 从一开始上机通电是无法直接启动操作系统的 , 这中间需要一个引导过程 , 嵌入式Linux系统同样离不开引导程序 , 这个启动程序就叫启动加载程序(Boot ...
- thttpd和cgilua安装与运行流程分析
安装 参考如下博文安装thttpd软件 http://blog.csdn.net/21aspnet/article/details/7045845 http://blog.csdn.net/drago ...
- 【转】Hostapd工作流程分析
[转]Hostapd工作流程分析 转自:http://blog.chinaunix.net/uid-30081165-id-5290531.html Hostapd是一个运行在用户态的守护进程,可以通 ...
- u-boot中nandflash初始化流程分析(转)
u-boot中nandflash初始化流程分析(转) 原文地址http://zhuairlunjj.blog.163.com/blog/static/80050945201092011249136/ ...
- Android7.0 Phone应用源码分析(二) phone来电流程分析
接上篇博文:Android7.0 Phone应用源码分析(一) phone拨号流程分析 今天我们再来分析下Android7.0 的phone的来电流程 1.1TelephonyFramework 当有 ...
随机推荐
- Nginx+Gunicorn+Supervisor部署Flask应用
Flask 内置了简单的 Web 环境,让我们在开发的时候只需要专注于应用实现,而真正要在生产环境运行时这个简单的 Web 环境就不够用了,还需要一系列操作才能让 Web 应用高效的运行起来.现在记录 ...
- 票房和口碑称霸国庆档,用 Python 爬取猫眼评论区看看电影《我和我的家乡》到底有多牛
今年的国庆档电影市场的表现还是比较强势的,两名主力<我和我的家乡>和<姜子牙>起到了很好的带头作用. <姜子牙>首日破 2 亿,一举刷新由<哪吒之魔童降世&g ...
- 082 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 01 构造方法-无参构造方法
082 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 01 构造方法-无参构造方法 本文知识点:构造方法-无参构造方法 说明:因为时间紧张, ...
- Java知识系统回顾整理01基础04操作符04位操作符
一.位操作符 位操作符在实际工作中用的并不常见,但是我比较纠结这些位操作.所以实际练习位操作符的每一个操作符的操作实例来理解其具体含义. 建议: 如果确实感兴趣,就看看,个人建议跳过这个章节. 真正工 ...
- ESP8266 玩板记
一.前言 esp8266的玩板记,后面应该会去更一些其他东西,这一块内容,这算是收官之战了. IoT,江湖有缘再相会 二.ESP8266实现WiFi杀手/钓鱼 这次的博客做的是一个娱乐性较强的项目. ...
- spring-boot-route(十一)数据库配置信息加密
Spring Boot最大的特点就是自动配置了,大大的减少了传统Spring框架的繁琐配置,通过几行简单的配置就可以完成其他组件的接入.比如你想要连接mysql数据库,只需要的配置文件里面加入mysq ...
- 4-K8S 部署Java应用及应用程序生命周期管理
1.在kubernetes中部署应用程序流程 准备项目源码-->编译构建-->产出war包,打包到镜像中-->推送到镜像仓库 获取源代码是开发人员提交代码的代码托管地址,有Git.S ...
- 在阿里云上搭建私有GIT仓库
在阿里云上搭建私有GIT仓库 年轻人就得好好学习,不能这么颓废 最近做项目练练手,用到了github, 但是github访问速度是真的慢啊,下载项目,下载一天了.所以呢,我是个成熟的人了,只好自己搭建 ...
- 实验五 Internet与网络工具的使用
实验五 Internet与网络工具的使用 [实验目的]⑴.FTP服务器的架设和客户端的使用. ⑵.使用云盘和云笔记应用 ⑶.运用QQ的远程协助功能. (4).默认安装foxmail软件,进行邮件的收发 ...
- scrapy LinkExtractors
class scrapy.linkextractors.LinkExtractor Link Extractors 的目的很简单: 提取链接。 每个LinkExtractor有唯一的公共方法是 ext ...