调试GPU时,遇到的死锁问题,具体的序列如下:
- cpu0上某线程T1调用了系统含有__KERNEL_ENTER的接口
- __KERNEL_ENTER中会获得内核锁,然后使能中断,这时内核锁是归T1线程持有
- 就在使能中断后,GPU中断来了,接着执行GPU中断程序(在cpu0上执行)
- 这时在cpu1上的线程T2获取了用户自定义的锁B
- 线程T2同样调用了系统含有__KERNEL_ENTER的接口
- 由于内核锁已经被cpu0上的T1线程持有,所以cpu1上的T2线程此时卡住
- 这时GPU中断程序中也要去获取用户自定义的锁B,但是锁B已经被cpu1上的T2线程持有
- 中断程序卡住
- 由于中断程序卡死,所以不会执行API_InterExit,也就不会调用调度程序,从而T1线程再也没有机会被调度执行
- 由于之前cpu0上的中断程序没退出,cpu0上的中断还处于关闭状态,可怜的tick中断也无法被执行了,更没法调度了
- 由于T1线程没可能再次执行,也就没可能释放内核锁了,此时整个系统GG
分析:
- 死锁的诱发原因是T1线程无法被调度执行,从而无法释放内核锁
- 在中断上下文中程序被spinlock卡死,从而导致中断程序无法正常结束(在实际案例中是由于在lock和unlock之间调用了信号量post操作)
- 如果中断程序能正常结束,那么T1线程就能被再次调度,从而解决死锁问题
解决方法:
- 第一种方法就是修改spinlock保护的临界区代码逻辑,不要使用带__KERNEL_ENTER的系统接口
- 第二种方法就是将中断处理放到中断延迟队列中去执行
在实际的案例中,使用了第二种方法,因为由于驱动程序的复杂性,可能导致用第一种方法会导致驱动逻辑的较大改动,从而带来较大的工作量。
2021年6月28日 23:05 1F
不错不错