内核printk的实现分析

本文详细分析了Linux内核中的printk函数实现,包括logbuf_lock、console_sem等同步机制,以及log_buf缓冲区的使用。printk首先将格式化的输出存入临时缓冲区,然后根据条件决定是否添加日志级别标签。接着,数据被复制到log_buf缓冲区,当控制台可调用时,通过console_sem信号量协调,调用console_drivers将数据发送到相应设备。通过对console_drivers结构体的注册和初始化,确保printk输出能够正确地发送到控制台。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


在这里还是主要分析一下printk实现的原理。


static spinlock_t logbuf_lock = SPIN_LOCK_UNLOCKED; //定义logbuf_lock,并初始化为unlock状态
static char log_buf[LOG_BUF_LEN];  //保存日志数据的缓冲区
#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
static DECLARE_MUTEX(console_sem); //定义全局互斥信号量console_sem并初始化为1


asmlinkage int printk(const char *fmt, ...)
{
 va_list args;
 unsigned long flags;
 int printed_len;
 char *p;
 static char printk_buf[1024];
 static int log_level_unknown = 1;


 if (oops_in_progress)  // default : oops_in_progress = 0
 { //oops_in_progress指示进程发生错误,只有在panic()函数中才等于1
  //所以一般情况下下两句都不运行
  /* If a crash is occurring, make sure we can't deadlock */
  spin_lock_init(&logbuf_lock); //初始化logbuf_lock
  /* And make sure that we print immediately */
  init_MUTEX(&console_sem); //初始化console_sem为互斥的信号量,初值为1
 }


 /* This stops the holder of console_sem just where we want him */
 spin_lock_irqsave(&logbuf_lock, flags);
 //一般spin_lock在单cpu中无效的,所以spin_lock_irqsave真正的作用是关中断 和保存状态寄存器。
 /* Emit the output into the temporary buffer */
 va_start(args, fmt);
 printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
 //先把数据格式化到printk_buf中去
 va_end(args);


 /*
  * Copy the output into log_buf.  If the caller didn't provide
  * appropriate log level tags, we insert them here
  */
 //emit_log_char 把字符存入log_buf中等待被发送,具体的参见下面的分析
 for (p = printk_buf; *p; p++) {
  if (log_level_unknown) {
   if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') {
    emit_log_char('<');
    emit_log_char(default_message_loglevel + '0');
    emit_log_char('>');
   }
 //如果没有提供<1>类似的日志级别,则在此加上<4>
 //我这里的default_message_loglevel=4
   log_level_unknown = 0;
  }
  emit_log_char(*p);
  if (*p == '\n') //每一行前面都需要加<4>之类的日志级别
   log_level_unknown = 1;
 }


 if (!arch_consoles_callable()) // unexecute
 {
  /* 控制台是否可调用,一般下面的不会被执行
   * On some architectures, the consoles are not usable
   * on secondary CPUs early in the boot process.
   */
  spin_unlock_irqrestore(&logbuf_lock, flags);
  goto out;
 }
 if (!down_trylock(&console_sem)) //lock ok
 {
  /* down_trylock获取信号量,lock则返回0,否则立即返回非0值
   * We own the drivers.  We can drop the spinlock and let
   * release_console_sem() print the text
   */
  spin_unlock_irqrestore(&logbuf_lock, flags);
  console_may_schedule = 0;
  release_console_sem(); 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值