D:LINUX内核层PRINTK实现原理
来源:互联网 发布:阿里云研究生学生认证 编辑:程序博客网 时间:2024/05/24 06:42
(最终调用上面注册的CONSOLE来输出调试信息)
LINUX内核源码版本:linux-3.0.86
Linux内核层printk函数用于输出内核调试信息。Printk->vprintk->log_prefix->
emit_log_char->log_start/log_end->console_unlock->call_console_drivers(_con_start, _log_end)->_call_console_drivers->__call_console_drivers->con->write(con, &LOG_BUF(start), end - start)上面printk输出信息的流程。直到调用到最低层的write函数就把数据从串口输出来了,其实就调用到上节介绍了的操控台。调用操控台中的写函数。上面函数需要注意的几个地方。
/* Emit the output into the temporary buffer */
printed_len += vscnprintf(printk_buf + printed_len,
sizeof(printk_buf) - printed_len, fmt, args);//输出信息暂存在printk_buf中。
p = printk_buf;
int current_log_level = default_message_loglevel;
CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
log_prefix当我们不在printk函数输出信息中添加级别的话函数会为其添加一个默认的输出信息级别4。
上面准备好了输出信息,则下面函数就来把准备好的数据输出来了。
static void _call_console_drivers(unsigned start,unsigned end, int msg_log_level)
{
if ((msg_log_level < console_loglevel || ignore_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_loglevel。如果我们的调试信息小于console_loglevel则输出。否则不能输出的。因此console_loglevel这个变量是可以通过外部来调节的。默认是7.默认输出所有调试信息的。ignore_loglevel如果这个定义了。则console_loglevel不起作用,也会输出所有调试信息。
sysrq_handle_loglevel->console_loglevel = i;可以通过文件系统层来调节允许输出调试信息级别。值越小能输出到操控台的信息就少,反之则越大。
/*
* Call the console drivers on a range of log_buf
*/
static void __call_console_drivers(unsigned start, unsigned end)
{
struct console *con;
for_each_console(con) {//轮询console_driver上一节注册的操控台。
if (exclusive_console && con != exclusive_console)//如果设置了调试用的操控台,则其它操控台不输出调试信息。
我们的平台是exclusive_console=s3c24xx_serial_console
continue;
if ((con->flags & CON_ENABLED) && con->write &&
(cpu_online(smp_processor_id()) ||
(con->flags & CON_ANYTIME)))
con->write(con, &LOG_BUF(start), end - start);
}
}//这部分代码完成真正的输出功能。con->write(con, &LOG_BUF(start), end - start);真正调用到的是s3c24xx_serial_console_write(s3c24xx_serial_console,&LOG_BUF(start), end - start)说明了当第一次注册时就会把缓冲的数据一次性完部输出。其后是每次调用时输出相关功能。Printk实现的了信号量的,每次只有一个外部能调用它输出,当在PIRINT执行中时就MUTEX了等待。
uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
port = &s3c24xx_serial_ports[co->index].port;
[0] = {
.port = {
.lock= __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
.iotype= UPIO_MEM,
.irq= IRQ_S3CUART_RX0,
.uartclk= 0,
.fifosize= 16,
.ops= &s3c24xx_serial_ops,
.flags= UPF_BOOT_AUTOCONF,
.line= 0,
}
},
cons_uart=等于在console_register注册时值,我们代码就会根据co->index=0等到为每一个串口终端输出数据。
s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
{
unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
while (!s3c24xx_serial_console_txrdy(port, ufcon))
barrier();
wr_regb(cons_uart, S3C2410_UTXH, ch);
}因此最终实际输出数据是由cons_uart=决定为一那一个串口。
通过上面代码可知中如查定义了多个操控台,则输出的为cons_uart=最后初始化它的。因为这个变量只存了最后一个。前面定义的操控台还是不能输出数据的。
兴趣交流群抠抠: 461283592
- D:LINUX内核层PRINTK实现原理
- Linux内核printk实现
- linux内核printk调试
- linux内核printk调试
- linux内核打印--printk
- linux内核printk调试
- linux内核之printk
- linux printk工作原理
- 内核printk的实现分析
- 内核printk的实现分析
- Linux内核调试printk()总结
- Linux 内核调试之 printk
- Linux内核 printk知多少
- Linux内核printk打印格式
- linux printk()的实现
- 浅析linux printk的实现
- Linux内核sys_poll实现原理
- Linux内核打印函数printk的使用说明
- IP地址与子网掩码总结,网络号、主机号、网络地址、主机地址实例分析
- 中央军委联勤保障部队成立大会在京举行 习近平授予军旗并致训词
- cocos2d-js 网络请求(GET)
- 【记录】安装ubuntu系统
- 学习RAC小记-适合给新手看的RAC用法总结
- D:LINUX内核层PRINTK实现原理
- Error:Execution failed for task ':clean'. > Unable to delete directory :\build\intermediates
- HDU 5468 Puzzled Elena(2015 ACM/ICPC Asia Regional Shanghai Online)
- mysql常用参数的含义
- Swift语法09.元组
- java集合框架系列---LinkedList
- csv文件格式的优点
- UIPageViewController替换方案
- Ubuntu16.10下安装php的ssh2扩展