美文网首页
2018-05-07(旧文整理)Printk实现流程

2018-05-07(旧文整理)Printk实现流程

作者: 杨廣xiang | 来源:发表于2018-05-07 13:58 被阅读0次

一、 初步结论
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缓冲区中的所有数据都输出到串口。

相关文章

  • 2018-05-07(旧文整理)Printk实现流程

    一、 初步结论1.如何把字符串放到缓存,如果从缓存写到串口。首先是在关中断,关调度,保持logbuf_lock自...

  • 旧文整理

    旧文整理 很久不在这里发文了,主要原因是才思枯竭。 今天偶然翻看以前的随笔,觉得不如拿出几篇旧作,聊以安抚一下自己...

  • layer-list 加载多个图层

    整理旧笔记 1、xml 资源实现

  • 乘客_旧文整理

    你看到的一切,并不是真实。只是因为别人想让你看到这些。 我是谁?我并不知道。 其实知道也没用。 它们告诉我,我是一...

  • 陪伴(旧文整理)

    转眼三年了,我陪伴了你三年。不!准确的说是你陪伴了我三年。 落叶满地的深秋,你如约而至在我的肚子里陪我一起挤地铁上...

  • 绚烂多彩的意识流程(旧文整理)

    ——用文艺心理学分析《离骚》 【提纲】一、我的理论依据。二、时代、诗人及《离骚》所传达的思想信息。三、《离骚》的内...

  • 2018-05-07(旧文整理)企业信息安全建设

    企业信息安全面临的威胁 今天,企业生产活动越来越依赖于信息系统,企业的发展壮大也需要信息系统的助力,因此,信息系统...

  • 陪伴2(旧文整理)

    我喝了一口水,砳仔用国王的口气说:现在我命令你可以喝一口水!我回答现在不想喝了,他接:我现在命令你可以不喝一口水!...

  • 云山云海(旧文整理)

    曾两上云顶,正好是白天和夜里,对上面玩的吃的没有什么印象,路途中有倒有惊艳的感觉。 第一次,夜里11...

  • Android日志打印(11)

    内核空间日志打印 日志保存 在linux内核中使用printk来实现日志打印输出且保存到/proc/kmsg,通过...

网友评论

      本文标题:2018-05-07(旧文整理)Printk实现流程

      本文链接:https://www.haomeiwen.com/subject/ffnmrftx.html