Android kernel printk概览

1. kernel\include\linux\printk.h

#define pr_notice(fmt, ...)     printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)

...

2. kernel\kernel\printk.c

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_emit(0, -1, NULL, 0, fmt, args);
    va_end(args);

    return r;
}
EXPORT_SYMBOL(printk);

...

asmlinkage int vprintk_emit(int facility, int level,

                const char *dict, size_t dictlen,
                const char *fmt, va_list args)
{
    static int recursion_bug;
    static char textbuf[LOG_LINE_MAX];
    char *text = textbuf;
    size_t text_len;
    enum log_flags lflags = 0;
    unsigned long flags;
    int this_cpu;
    int printed_len = 0;

    boot_delay_msec(level);
    printk_delay();

    /* This stops the holder of console_sem just where we want him */
    local_irq_save(flags);
    this_cpu = smp_processor_id();

    /*
     * Ouch, printk recursed into itself!
     */
    if (unlikely(logbuf_cpu == this_cpu)) {
        /*
         * If a crash is occurring during printk() on this CPU,
         * then try to get the crash message out but make sure
         * we can't deadlock. Otherwise just return to avoid the
         * recursion and return - but flag the recursion so that
         * it can be printed at the next appropriate moment:
         */
        if (!oops_in_progress && !lockdep_recursing(current)) {
            recursion_bug = 1;
            goto out_restore_irqs;
        }
        zap_locks();
    }

    lockdep_off();
    raw_spin_lock(&logbuf_lock);
    logbuf_cpu = this_cpu;

    if (recursion_bug) {
        static const char recursion_msg[] =
            "BUG: recent printk recursion!";

        recursion_bug = 0;
        printed_len += strlen(recursion_msg);
        /* emit KERN_CRIT message */
        log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
              NULL, 0, recursion_msg, printed_len);
    }

    /*
     * The printf needs to come first; we need the syslog
     * prefix which might be passed-in as a parameter.
     */
    text_len = vscnprintf(text, sizeof(textbuf), fmt, args);

    /* mark and strip a trailing newline */
    if (text_len && text[text_len-1] == '\n') {
        text_len--;
        lflags |= LOG_NEWLINE;
    }

    /* strip kernel syslog prefix and extract log level or control flags */
    if (facility == 0) {
        int kern_level = printk_get_level(text);

        if (kern_level) {
            const char *end_of_header = printk_skip_level(text);
            switch (kern_level) {
            case '0' ... '7':
                if (level == -1)
                    level = kern_level - '0';
            case 'd':    /* KERN_DEFAULT */
                lflags |= LOG_PREFIX;
            case 'c':    /* KERN_CONT */
                break;
            }
            text_len -= end_of_header - text;
            text = (char *)end_of_header;
        }
    }

#ifdef CONFIG_EARLY_PRINTK_DIRECT
    printascii(text);
#endif

    if (level == -1)
        level = default_message_loglevel;

    if (dict)
        lflags |= LOG_PREFIX|LOG_NEWLINE;

    if (!(lflags & LOG_NEWLINE)) {
        /*
         * Flush the conflicting buffer. An earlier newline was missing,
         * or another task also prints continuation lines.
         */
        if (cont.len && (lflags & LOG_PREFIX || cont.owner != current))
            cont_flush(LOG_NEWLINE);

        /* buffer line if possible, otherwise store it right away */
        if (!cont_add(facility, level, text, text_len))
            log_store(facility, level, lflags | LOG_CONT, 0,
                  dict, dictlen, text, text_len);
    } else {
        bool stored = false;

        /*
         * If an earlier newline was missing and it was the same task,
         * either merge it with the current buffer and flush, or if
         * there was a race with interrupts (prefix == true) then just
         * flush it out and store this line separately.
         */
        if (cont.len && cont.owner == current) {
            if (!(lflags & LOG_PREFIX))
                stored = cont_add(facility, level, text, text_len);
            cont_flush(LOG_NEWLINE);
        }

        if (!stored)
            log_store(facility, level, lflags, 0,
                  dict, dictlen, text, text_len);
    }
    printed_len += text_len;

    /*
     * Try to acquire and then immediately release the console semaphore.
     * The release will print out buffers and wake up /dev/kmsg and syslog()
     * users.
     *
     * The console_trylock_for_printk() function will release 'logbuf_lock'
     * regardless of whether it actually gets the console semaphore or not.
     */
    if (console_trylock_for_printk(this_cpu))
        console_unlock();

    lockdep_on();
out_restore_irqs:
    local_irq_restore(flags);

    return printed_len;
}
EXPORT_SYMBOL(vprintk_emit);




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值