Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15490080
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: LINUX

2008-08-16 21:44:11

浅析printk的emit_log_char()算法具体实现

【浅析2.6.24内核printk函数】


static unsigned long log_start;    /* Index into log_buf: next char to be read by syslog() */
static unsigned long con_start;    /* Index into log_buf: next char to be sent to consoles */
static unsigned long log_end;    /* Index into log_buf: most-recently-written-char + 1 */
#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
static int log_buf_len = __LOG_BUF_LEN;//有符号数


static void emit_log_char(char c)
{
    LOG_BUF(log_end) = c;
    log_end++;
//很明显log_end是一个index索引值,会一直使用unsigned无符号类型++下去,++之后log_end表示当前空闲位置索引
//log_start和log_end组成一个间距固定为log_buf_len的滑动窗体,所以log_end可以用来记录从printk输出的所有字符总数
    if (log_end - log_start > log_buf_len)
//是有符号比较,所以对于log_start=0xfffffff8,log_end=0x10,log_end-log_start将等于距离为0x18
//不过就算是无符号比较,对于long类型,32为cpu处理器,那么当到达32位最大数据时,也就等于距离
        log_start = log_end - log_buf_len;
//con_start为当前要打印数据的开始位置索引,如果log_end空闲数据指针和con_start的间距等于log_buf_len,
//说明下一次在进行数据提交的话,将覆盖log_start指向的字符,但是因为等于,所以实际覆盖动作还并没有发生
//直到大于log_buf_len长度,如果log_end空闲数据指针和con_start的间距超过了
//log_buf_len,说明本次LOG_BUF(log_end)操作[其实是log_end - 1],即
//(idx) & LOG_BUF_MASK操作已经等于con_start对应的con_start & LOG_BUF_MASK值,
//所以这时con_start指向的最老的数据已经被log_end覆盖,故需要将con_start指向次老数据,
//所以执行con_start = log_end - log_buf_len;操作.
    if (log_end - con_start > log_buf_len)
        con_start = log_end - log_buf_len;
    if (logged_chars < log_buf_len)
        logged_chars++;
}

#define console_loglevel (console_printk[0])
#define default_message_loglevel (console_printk[1])
#define minimum_console_loglevel (console_printk[2])
#define default_console_loglevel (console_printk[3])

call_console_drivers=>_call_console_drivers=>
static void _call_console_drivers(unsigned long start,
                unsigned long end, int msg_log_level)
{
    if ((msg_log_level < console_loglevel || ignore_loglevel) &&
            console_drivers && start != end) {
//1.符合console的打印输出级别msg_log_level < console_loglevel
//2.存在console_drivers驱动
//3.数据还没有结束start != end
        if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
            /* wrapped write */
//end小于start,说明有了wrap,分为两段,
//<1>start_index=>log_buf_len末尾
//<2>0=>end_index
            __call_console_drivers(start & LOG_BUF_MASK,
                        log_buf_len);
            __call_console_drivers(0, end & LOG_BUF_MASK);
        } else {
            __call_console_drivers(start, end);
        }
    }
}
static void __call_console_drivers(unsigned long start, unsigned long end)
{
    struct console *con;

    for (con = console_drivers; con; con = con->next) {
        if ((con->flags & CON_ENABLED) && con->write &&
                (cpu_online(smp_processor_id()) ||
                (con->flags & CON_ANYTIME)))
//向console_drivers链表上,所有登记的console控制台发送该段报文
            con->write(con, &LOG_BUF(start), end - start);
    }
}

release_console_sem=>如果console_suspended了,那么不会打log,直接返回.
void release_console_sem(void)
{
    unsigned long flags;
    unsigned long _con_start, _log_end;
    unsigned long wake_klogd = 0;

    if (console_suspended) {//console被suspend,直接返回
        up(&secondary_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);
        call_console_drivers(_con_start, _log_end);
        local_irq_restore(flags);
    }
    console_locked = 0;
    up(&console_sem);
    spin_unlock_irqrestore(&logbuf_lock, flags);
    if (wake_klogd)
        wake_up_klogd();
}

void suspend_console(void)
{
    if (!console_suspend_enabled)
        return;
    printk("Suspending console(s)\n");
    acquire_console_sem();
    console_suspended = 1;
}

阅读(2887) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~