文章目录
1. pr_fmt
在阅读Linux
内核或其他开源代码时,在文件的开始部分,通常能看到类似如下代码。但是代码中又没有看到使用的地方。
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <...>
#include <...>
其实pr_fmt
是通常和大名鼎鼎的printk
一起来合作实现其他宏,比较常见的就是pr_*()
系列宏,另外一些模块或驱动中也会利用pr_fmt
来输出日志信息。使用pr_fmt
可以在要输出的信息前再添加额外的信息。在include/linux/printk.h
中可以看到pr_fmt
的身影。
/**
* pr_fmt - used by the pr_*() macros to generate the printk format string
* @fmt: format string passed from a pr_*() macro
*
* This macro can be used to generate a unified format string for pr_*()
* macros. A common use is to prefix all pr_*() messages in a file with a common
* string. For example, defining this at the top of a source file:
*
* #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
*
* would prefix all pr_info, pr_emerg... messages in the file with the module
* name.
*/
#ifndef pr_fmt
#define pr_fmt(fmt) fmt
#endif
如果在#include <linux/printk.h>
之前没有定义pr_fmt
,include/linux/printk.h
中会将pr_fmt(fmt)
定义为fmt
,也就是输出信息的原始格式。如果在#include <linux/printk.h>
之后定义pr_fmt
,编译时就会提示重复定义警告或错误。所以通常来说,对pr_fmt
的定义都是放到了文件的最前端。
2. 常用pr_fmt
定义
2.1. 打印模块名、函数名和行号
KBUILD_MODNAME
是编译时通过编译选项指定的,无需自己定义。
#define pr_fmt(fmt) \
KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
2.2. 打印CPU号
使用raw_smp_processor_id
需要包含linux/smp.h
。
#define pr_fmt(fmt) \
KBUILD_MODNAME ": <C%u> " fmt, raw_smp_processor_id()
2.3. 打印线程pid和线程名
线程的task_struct
使用current
宏来获取,需要包含linux/sched.h
。
#define pr_fmt(fmt) \
"{t%d-%s} " fmt, current->pid, current->comm
2.4. 打印进程pid和进程名
进程的task_struct
可以通过current->group_leader
来获取。
#define pr_fmt(fmt) \
"{p%d-%s} " fmt, \
current->group_leader->pid, current->group_leader->comm
2.5. 打印进程pid和线程pid
进程pid current->tgid
与current->group_leader->pid
相同。
#define pr_fmt(fmt) \
"{p%d:t%d} " fmt, current->tgid, current->pid
2.6. 大杂烩
#define pr_fmt(fmt) \
KBUILD_MODNAME ": <C%u>{p%d-%s}{t%d-%s}[%s:%d] " fmt, raw_smp_processor_id(), \
current->group_leader->pid, current->group_leader->comm, \
current->pid, current->comm, __func__, __LINE__
3. 常见pr_*()接口
三种类型的接口说明如下:
- pr_xxx:按照pr_fmt指定的格式输出日志。
- pr_xxx_once:日志只输出一次。
- pr_xxx_ratelimited:通常来说终端是慢速设备,pr_xxx_ratelimited可以限制日志输出速率,避免信息过多导致CPU阻塞。
pr_xxx | pr_xxx_once | pr_xxx_ratelimited | loglevel | description |
---|---|---|---|---|
pr_emerg | pr_emerg_once | pr_emerg_ratelimited | KERN_EMERG | system is unusable |
pr_alert | pr_alert_once | pr_alert_ratelimited | KERN_ALERT | action must be taken immediately |
pr_crit | pr_crit_once | pr_crit_ratelimited | KERN_CRIT | critical conditions |
pr_err | pr_err_once | pr_err_ratelimited | KERN_ERR | error conditions |
pr_warn | pr_warn_once | pr_warn_ratelimited | KERN_WARNING | warning conditions |
pr_notice | pr_notice_once | pr_notice_ratelimited | KERN_NOTICE | normal but significant condition |
pr_info | pr_info_once | pr_info_ratelimited | KERN_INFO | informational |
pr_devel | pr_devel_once | pr_devel_ratelimited | KERN_DEBUG | debug-level message conditionally |
pr_debug | pr_debug_once | pr_debug_ratelimited | KERN_DEBUG/dynamic | (dynamic) debug-level message conditionally |
3.1. pr_devel
和pr_debug
pr_*()
中比较特殊的是pr_devel
和pr_debug
,它们需要在特定条件下才会有实际作用。
pr_devel
在没有定义DEBUG
的情况下不做任何工作。pr_debug
在pr_devel
的基础上增加了动态调试部分,如果使能了动态调试,则实际为dynamic_pr_debug
,否则与pr_devel
效果一致。
#ifdef DEBUG
#define pr_devel(fmt, ...) \
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#else
#define pr_devel(fmt, ...) \
no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#endif
/* If you are writing a driver, please use dev_dbg instead */
#if defined(CONFIG_DYNAMIC_DEBUG) || \
(defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE))
#include <linux/dynamic_debug.h>
#define pr_debug(fmt, ...) \
dynamic_pr_debug(fmt, ##__VA_ARGS__)
#elif defined(DEBUG)
#define pr_debug(fmt, ...) \
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#else
#define pr_debug(fmt, ...) \
no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#endif