在这里还是主要分析一下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();