接下去看printk
还是宏 CONFIG_PRINTK 在s3c2410中定义了改宏
#ifdef CONFIG_PRINTK
asmlinkage int vprintk(const char *fmt, va_list args)
__attribute__ ((format (printf, 1, 0)));
asmlinkage int printk(const char * fmt, ...)
__attribute__ ((format (printf, 1, 2)));
#else
static inline int vprintk(const char *s, va_list args)
__attribute__ ((format (printf, 1, 0)));
static inline int vprintk(const char *s, va_list args) { return 0; }//直接返回
static inline int printk(const char *s, ...)
__attribute__ ((format (printf, 1, 2)));
static inline int printk(const char *s, ...) { return 0; } //直接返回
#endif
继续往下看
asmlinkage int printk(const char *fmt, ...)
{
va_list args;
int r;
va_start(args, fmt);
r = vprintk(fmt, args);
va_end(args);
return r;
}
vprintk如下:终于来了个大家伙!该函数负责解析并组成打印格式,
asmlinkage int vprintk(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;
preempt_disable(); //空操作
if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id())
/* If a crash is occurring during printk() on this CPU,
* make sure we can't deadlock */
zap_locks(); // 初始化锁logbuf_lock和互斥量console_sem
/* This stops the holder of console_sem just where we want him */
spin_lock_irqsave(&logbuf_lock, flags); //加锁
printk_cpu = smp_processor_id();
/* Emit the output into the temporary buffer */
printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
// 将打印信息拷贝到printk_buf缓冲中,printk("%d, %s", 5, "hello") printk_buf中将是5,hello格式化后的数据不带'/0'
/*
* Copy the output into log_buf. If the caller didn't provide
* appropriate log level tags, we insert them here
*/
for (p = printk_buf; *p; p++) {
if (log_level_unknown) { //打印级别未知,则添家打印级别
/* log_level_unknown signals the start of a new line */
if (printk_time) { //由于没有定义CONFIG_PRINTK_TIME宏 printk_time = 0;
int loglev_char;
char tbuf[50], *tp;
unsigned tlen;
unsigned long long t;
unsigned long nanosec_rem;
/*
* force the log level token to be
* before the time output.
*/
if (p[0] == '<' && p[1] >='0' &&
p[1] <= '7' && p[2] == '>') {
loglev_char = p[1];
p += 3;
printed_len += 3;
} else {
loglev_char = default_message_loglevel
+ '0';
}
t = printk_clock();
nanosec_rem = do_div(t, 1000000000);
tlen = sprintf(tbuf,
"<%c>[%5lu.%06lu] ",
loglev_char,
(unsigned long)t,
nanosec_rem/1000);
for (tp = tbuf; tp < tbuf + tlen; tp++)
emit_log_char(*tp);
printed_len += tlen - 3;
} else { //由于printk_time = 0,直接跳转到这里
if (p[0] != '<' || p[1] < '0' ||
p[1] > '7' || p[2] != '>') { // 如果没有设置打印级别,那么默认0级
emit_log_char('<');
emit_log_char(default_message_loglevel
+ '0');
emit_log_char('>');
}
printed_len += 3;
}
log_level_unknown = 0;
if (!*p)
break;
}
emit_log_char(*p); //打印信息已经保存到log_buf中
if (*p == '/n') //如遇到 '/n' 则表示一条打印结束,那么打印级别需要从新设置
log_level_unknown = 1;
}
if (!cpu_online(smp_processor_id())) {
/*
* Some console drivers may assume that per-cpu resources have
* been allocated. So don't allow them to be called by this
* CPU until it is officially up. We shouldn't be calling into
* random console drivers on a CPU which doesn't exist yet..
*/
printk_cpu = UINT_MAX;
spin_unlock_irqrestore(&logbuf_lock, flags);
goto out;
}
if (!down_trylock(&console_sem)) {
console_locked = 1;
/*
* We own the drivers. We can drop the spinlock and let
* release_console_sem() print the text
*/
printk_cpu = UINT_MAX;
spin_unlock_irqrestore(&logbuf_lock, flags);
console_may_schedule = 0;
release_console_sem();
} else {
/*
* Someone else owns the drivers. We drop the spinlock, which
* allows the semaphore holder to proceed and to call the
* console drivers with the output which we just produced.
*/
printk_cpu = UINT_MAX;
spin_unlock_irqrestore(&logbuf_lock, flags); //释放锁,打印信息已经保存到log_buf中,等待打印
}
out:
preempt_enable();
return printed_len;
}
printk和printf不同,他首先输出到系统的一个缓冲区内,大约4k,如果登记了console,则调用console->wirte函数输出,否则就一直在buffer里呆着。所以,用printk输出的信息,如果超出了4k,会冲掉前面的。在系统引导起来后,用dmesg看的也就是这个buffer中的东东。
此时的信息还在buf中躺着呢。。因为console还没有初始化。。。