Printk实现流程

一、初步结论
1.如何把字符串放到缓存,如何从缓存写到串口。
首先是在关中断,关调度,保持logbuf_lock自旋锁的情况下,将数据格式化后,放到printk_buf缓冲区,其大小为1K,也就是说,每次printk只能打印1K的内容。格式化完毕后,将数据再复制到log_buf缓冲区。由于在向串口输出的过程中,会暂时打开自旋锁,所以在SMP下,其他CPU可能继续向log_buf中存放数据,并由驱动输出。简单的说:调用一次printk,需要打印的并不仅仅是本次printk需要输出的内容,还可能有其他CPU上输出的内容。
从缓存中输出到真实的设备是由注册的控制台个数决定的。注册多少个设备,就向多少个设备输出。也就是说,如果注册了两个串口控制台,那么关中断的时间就会增加一倍。
2.采用中断还是轮询。
采用的是轮询方式。

二、代码流程详细分析
Printk的主要流程由vprintk辅助函数实现。
Vprintk的流程如下:

1.关抢占。这是因为需要调用smp_processor_id,如果不关调度,并且是在异常或者内核线程中调用printk的话,可能会导致任务飘移到其他CPU,从而导致后续逻辑判断错误。
2.如果当前上下文是在异常中,那么异常可能是printk引起的,由于后续会使用logbuf_lock自旋锁,为了防止自旋锁嵌套,导致系统死锁,调用zap_locks,复位自旋锁。
3.关中断,并获得logbuf_lock自旋锁,以保护printk_buf缓冲区,这样即使是在SMP上,printk打印出来的内容都不会交错输出。
4.将格式化的信息输出到printk_buf缓冲区,并复制到log_buf。
5.使用down_trylock非阻塞的申请console_sem信号量。视情况进入以下处理流程:
A:如果申请成功,则将log_buf中的内容输出到物理设备上。
B:如果申请失败,则开中断并释放自旋锁,并退出。本次输出到printk_buf缓冲区的内容,由其他printk执行路径输出到物理设备上。所以,某次printk输出到物理设备上的内容,并不一定仅仅是本次传递给printk的内容,还有可能是其他CPU上的printk输出到缓冲区中的内容。

当printk向缓冲区输出申请console_sem信号量成功后,printk会向物理设备输出,在这个过程中,会临时释放自旋锁,以允许其他CPU向缓冲区中输出内容。具体流程如下:
1.暂时释放logbuf_lock自旋锁,这样,其他CPU可以向log_buf缓冲区中输出数据。
2.调用release_console_sem向物理设备输出内容。
3.release_console_sem首先在循环执行如下流程:
A:得到当前log_buf缓冲区的起始地址和物理地址。如果没有新的数据,则退出。新的数据可能是其他cpu调用printk输出到缓冲区中的。
B:打开自旋锁,允许其他CPU向缓冲区中输出数据。
C:调用call_console_drivers将当前缓冲区中的内容输出到物理设备。本次输出的内容,不包含释放自旋锁后,其他CPU向缓冲区中输出的内容。
4. 循环结束后,release_console_sem判断本次printk是否确实输出了数据(当printk参数为空串时,可能没有数据),如果有数据输出,就唤醒klogd进程。

call_console_drivers函数首先将输出内容按行分拆,并将每行数据传递给当前注册的所有控制台设备,调用控制台驱动将数据打印出来。由于整个过程都处于关中断状态,所以,只要某个注册的控制台驱动是慢速设备,都会影响到关中断的时间。更为严重的是:如果某个CPU在调用printk输出期间,其他CPU也准备向控制台输出,那么其他CPU也会因为申请不到logbuf_lock自旋锁而处于忙等状态。

串口驱动函数:
耗时的过程是向串口等慢速设备输出数据的过程。由于printk可以在中断中使用,所以也决定了驱动不能采用中断方式,而必须是轮询串口的方式。

8250串口驱动回调函数serial8250_console_write实现了控制台write回调。这个函数的流程如下:
1.首先调用一下NMI软件狗回调函数。看来串口驱动已经意识到慢速设备对系统的影响了。但是这个回调没有办法解决硬件狗的问题。
2.关中断。
3.对需要输出的每个字符,回调serial8250_console_putchar函数。
4.最费时的地方就在serial8250_console_putchar中。它调用wait_for_xmitr(up, UART_LSR_THRE);一句,轮询串口状态。直到串口可写,才向串口输出一个字符。
5.恢复中断状态。实际上,在printk上下文中,中断此时仍然是关闭的,直到log_buf缓冲区中的所有数据都输出到串口。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值