- 说明
之前看过5.10版本的dump_stack对SMP特性的支持,本文分析mainline内核最新的6.12rc3版本中的实现。
实现如下:
对内核栈帧的回溯主要通过__dump_stack函数进行。对SMP特性的支持主要体现在printk_cpu_sync_get_irqsave和printk_cpu_sync_put_irqrestore函数中。当然,如果CPU处于panic状态,这两个函数不会执行。
2.printk_cpu_sync_get_irqsave
printk_cpu_sync_get_irqsave事实上是个宏定义,其定义为:
首先屏蔽中断保留flag。
之后调用__printk_cpu_sync_try_get。
__printk_cpu_sync_try_get的实现为:
这个函数对两种情况进行处理:
- 如果在所有CPU上dump_stack还没有被调用过,直接返回1。
- 如果dump_stack已经在当前CPU上调用了,则允许抢占,可以再次调用dump_stack。printk_cpu_sync_nested是个原子变量,初始化值是0,这种情况下会被置1。表示dump_stack已经被嵌套调用了。
这里还有另一个原子变量printk_cpu_sync_owner。这个变量初始化值为-1。
其值为-1,表示dump_stack还没有被任何CPU上的进程调用。一旦一个进程调用了dump_stack,这个变量就会被标记为这个CPU的CPUID。
如果dump_stack已经被调用,其他CPU上也想调用,则会像自旋锁一样等待。
__printk_cpu_sync_wait的实现如下:
printk_cpu_sync_owner的值不是-1,说明正在被调用中,一直等待其变为-1。
3.printk_cpu_sync_put_irqrestore
实现为:
首先调用__printk_cpu_sync_put,该函数实现为:
首先检查当前CPU上的dump_stack函数有没有嵌套调用,如果是,将printk_cpu_sync_nested变量减一然后返回。最后将printk_cpu_sync_owner重新设置为-1,这样让其他CPU上调用dump_stack的任务可以停止等待得到执行的机会。
4.总结
最新版本的dump_stack对调用栈回溯的多线程保护本质上是个可重入的自旋锁,允许单个CPU上嵌套的调用,但是同一时间只能在一个CPU上调用dump_stamp。