【Linux内核】pr_fmt介绍

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_fmtinclude/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->tgidcurrent->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_xxxpr_xxx_oncepr_xxx_ratelimitedlogleveldescription
pr_emergpr_emerg_oncepr_emerg_ratelimitedKERN_EMERGsystem is unusable
pr_alertpr_alert_oncepr_alert_ratelimitedKERN_ALERTaction must be taken immediately
pr_critpr_crit_oncepr_crit_ratelimitedKERN_CRITcritical conditions
pr_errpr_err_oncepr_err_ratelimitedKERN_ERRerror conditions
pr_warnpr_warn_oncepr_warn_ratelimitedKERN_WARNINGwarning conditions
pr_noticepr_notice_oncepr_notice_ratelimitedKERN_NOTICEnormal but significant condition
pr_infopr_info_oncepr_info_ratelimitedKERN_INFOinformational
pr_develpr_devel_oncepr_devel_ratelimitedKERN_DEBUGdebug-level message conditionally
pr_debugpr_debug_oncepr_debug_ratelimitedKERN_DEBUG/dynamic(dynamic) debug-level message conditionally

3.1. pr_develpr_debug

pr_*()中比较特殊的是pr_develpr_debug,它们需要在特定条件下才会有实际作用。

  1. pr_devel在没有定义DEBUG的情况下不做任何工作。
  2. pr_debugpr_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
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值