Wednesday, February 11, 2009

printk

printk可以在任何上下文中调用.其有16K(具体数值menuconfig可以配置)的ring buffer. dmesg显示的就是这部分数据.故如果打印过多,dmesg只能查看到最新的打印,无法得到自开机以来全部的内核打印.

printk的信息级别:
#define    KERN_EMERG    "<0>"    /* system is unusable            */
#define    KERN_ALERT    "<1>"    /* action must be taken immediately    */
#define    KERN_CRIT    "<2>"    /* critical conditions            */
#define    KERN_ERR    "<3>"    /* error conditions            */
#define    KERN_WARNING    "<4>"    /* warning conditions            */
#define    KERN_NOTICE    "<5>"    /* normal but significant condition    */
#define    KERN_INFO    "<6>"    /* informational            */
#define    KERN_DEBUG    "<7>"    /* debug-level messages            */

当不指定级别时,kernel会默认成KERN_WARNING级别

printk最后直接调用或间接调用_call_console_drivers把字符输出到console. 只代码中可以看到:
只有msg_log_level小于console_loglevel的信息才会输出.kernel默认console_loglevel为7( 即 KERN_DEBUG, 故KERN_DEBUG的信息不会输出到console).
/*
 * Write out chars from start to end - 1 inclusive
 */
static void _call_console_drivers(unsigned long start,
                unsigned long end, int msg_log_level)
{
    if (msg_log_level < console_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);
        }
    }
}

故要查看在console上看不到的内核信息,即 msg level >= console_loglevel 的信息,可以使用dmesg.

要配置console_loglevel,可以在启动kernel时加上loglevel=n这个选项.也可以在应用层通过syslog系统调用(glibc对应的函数为klogctl)来动态修改.


printk 支持同时向多个console输出字符, 其维护一个console_drivers链表,分别调用
void register_console(struct console *console)
int unregister_console(struct console *console)
来添加或删除console.
其实这个console只是提供内核打印输出的功能.  在串口驱动初始化时, 一般会注册一个console.


No comments: