浅析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;
}
|