printk的定义
可变参数 参考va_list,va_start,va_arg,va_end可变参数
asmlinkage int printk(const char *fmt, ...) { va_list args; //可变参数链表 int r; #ifdef CONFIG_KGDB_KDB if (unlikely(kdb_trap_printk)) { va_start(args, fmt); r = vkdb_printf(fmt, args); va_end(args); return r; } #endif va_start(args, fmt); //获取第一个可变参数 r = vprintk(fmt, args); //调用vprintk函数 va_end(args); //释放可变参数链表指针 return r; }
vprintk函数
asmlinkage int vprintk(const char *fmt, va_list args) { int printed_len = 0; int current_log_level = default_message_loglevel; unsigned long flags; int this_cpu; char *p; boot_delay_msec(); printk_delay(); preempt_disable(); raw_local_irq_save(flags); this_cpu = smp_processor_id(); if (unlikely(printk_cpu == this_cpu)) { if (!oops_in_progress) { recursion_bug = 1; goto out_restore_irqs; } zap_locks(); } lockdep_off(); spin_lock(&logbuf_lock); printk_cpu = this_cpu; if (recursion_bug) { recursion_bug = 0; strcpy(printk_buf, recursion_bug_msg); printed_len = strlen(recursion_bug_msg); } printed_len += vscnprintf(printk_buf + printed_len,sizeof(printk_buf) - printed_len, fmt, args); p = printk_buf; if (p[0] == '<') { //处理打印级别字段 unsigned char c = p[1]; if (c && p[2] == '>') { switch (c) { case '0' ... '7': /* loglevel */ current_log_level = c - '0'; case 'd': /* KERN_DEFAULT */ if (!new_text_line) { emit_log_char('\n'); new_text_line = 1; } case 'c': /* KERN_CONT */ p += 3; break; } } } for ( ; *p; p++) { if (new_text_line) { /* Always output the token */ emit_log_char('<'); emit_log_char(current_log_level + '0'); emit_log_char('>'); printed_len += 3; new_text_line = 0; if (printk_time) { //打印时间信息 /* Follow the token with the time */ char tbuf[50], *tp; unsigned tlen; unsigned long long t; unsigned long nanosec_rem; t = cpu_clock(printk_cpu); nanosec_rem = do_div(t, 1000000000); tlen = sprintf(tbuf, "[%5lu.%06lu] ",(unsigned long) t,nanosec_rem / 1000); for (tp = tbuf; tp < tbuf + tlen; tp++) emit_log_char(*tp); printed_len += tlen; } if (!*p) break; } emit_log_char(*p); if (*p == '\n') new_text_line = 1; } if (acquire_console_semaphore_for_printk(this_cpu)) release_console_sem(); lockdep_on(); out_restore_irqs: raw_local_irq_restore(flags); preempt_enable(); return printed_len; }
接着调用release_console_sem函数
void release_console_sem(void) { unsigned long flags; unsigned _con_start, _log_end; unsigned wake_klogd = 0; if (console_suspended) { up(&console_sem); return; } console_may_schedule = 0; for ( ; ; ) { spin_lock_irqsave(&logbuf_lock, flags); wake_klogd |= log_start - log_end; if (con_start == log_end) break; /* Nothing to print */ _con_start = con_start; _log_end = log_end; con_start = log_end; /* Flush */ spin_unlock(&logbuf_lock); stop_critical_timings(); /* don't trace print latency */ call_console_drivers(_con_start, _log_end); start_critical_timings(); local_irq_restore(flags); } console_locked = 0; up(&console_sem); spin_unlock_irqrestore(&logbuf_lock, flags); if (wake_klogd) wake_up_klogd(); } EXPORT_SYMBOL(release_console_sem);
调用call_console_drivers函数
static void call_console_drivers(unsigned start, unsigned end) { unsigned cur_index, start_print; static int msg_level = -1; BUG_ON(((int)(start - end)) > 0); cur_index = start; start_print = start; while (cur_index != end) { if (msg_level < 0 && ((end - cur_index) > 2) &&LOG_BUF(cur_index + 0) == '<' &&LOG_BUF(cur_index + 1) >= '0' &&LOG_BUF(cur_index + 1) <= '7' &&LOG_BUF(cur_index + 2) == '>') { msg_level = LOG_BUF(cur_index + 1) - '0'; cur_index += 3; start_print = cur_index; } while (cur_index != end) { char c = LOG_BUF(cur_index); cur_index++; if (c == '\n') { if (msg_level < 0) { msg_level = default_message_loglevel; } _call_console_drivers(start_print, cur_index, msg_level); msg_level = -1; start_print = cur_index; break; } } } _call_console_drivers(start_print, end, msg_level); }
_call_console_drivers函数
static void _call_console_drivers(unsigned start,unsigned end, int msg_log_level) { if ((msg_log_level < console_loglevel || ignore_loglevel) && console_drivers && start != end) { if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) { /* wrapped write */ __call_console_drivers(start & LOG_BUF_MASK,log_buf_len); __call_console_drivers(0, end & LOG_BUF_MASK); } else { __call_console_drivers(start, end); } } }
__call_console_drivers函数
遍历console_drivers数组
#define for_each_console(con) \ for (con = console_drivers; con != NULL; con = con->next)
调用console的写方法
static void __call_console_drivers(unsigned start, unsigned end) { struct console *con; for_each_console(con) { if ((con->flags & CON_ENABLED) && con->write &&(cpu_online(smp_processor_id()) ||(con->flags & CON_ANYTIME))) con->write(con, &LOG_BUF(start), end - start); //调用console的写方法 } }
console_drivers链表在register_console中会设置
二 console 设备驱动