问题现象描述:
BDJ光盘播放程序(ProcBDJ)与Youtube播放程序(ProcY)相互切换时,系统挂机(Hangup)
问题调查 Step1:
首先通过对比问题发生时与不发生时的Log文件,发现系统在启动DirectFB时挂机。
问题调查Step2:
进一步分析DirectFB的启动过程:(代码版本0.9.25)
文件dfb/src/core/Core.c 行287
dfb_core_create()
↓
dfb/lib/fusion/Arena.c 行502
函数fusion_arena_enter()
↓
dfb/src/core/Core.c 行916
函数dfb_core_arena_initialize()
↓
dfb/src/core/Core.c 行839
函数dfb_core_initialize()
↓
dfb/src/core/core_parts.c 行72
函数dfb_core_part_initialize()
↓
dfb/systems/fbdev/Fbdev.c 行446
函数system_initialize()
↓
dfb/systems/fbdev/vt.c 行177
函数dfb_vt_initialize()
↓
while (ioctl( dfb_vt->fd0,VT_WAITACTIVE, dfb_vt->num ) < 0) { // Hangup
开始调查时,一直不是很明白为什么会在这里挂住。
因为代码的前几行有如下代码:
while (ioctl( dfb_vt->fd0,VT_ACTIVATE, dfb_vt->num ) < 0)
代码上暂时看不出原因,但凭着多年的经验,直观上感觉是console的多进程共享使用冲突。
暂时解决方案:
DirectFB的配置文件(.directfbrc)文件里添加如下选项: no-vt
进一步分析linux内核,发现Block的原因如下:
正常流程:
dfb/systems/fbdev/vt.c 行167
↓
函数dfb_vt_initialize
while (ioctl( dfb_vt->fd0,VT_ACTIVATE, dfb_vt->num ) < 0) {
↓
kernel/linux-2.6.21.5/drivers/char/vt.c
执行LINUX Kernel的set_console函数
↓
kernel/linux-2.6.21.5/drivers/char/vt.c行2208
执行schedule_console_callback
↓
kernel/linux-2.6.21.5/drivers/char/vt.c 行2163
函数console_callback→执行change_console函数
↓
kernel/linux-2.6.21.5/drivers/char/vt_ioctl.c 行1245
函数complete_change_console→vt切换OK。
dfb/systems/fbdev/vt.c 行177近く
函数: dfb_vt_initialize
while (ioctl( dfb_vt->fd0,VT_WAITACTIVE, dfb_vt->num ) < 0)
↓
kernel/linux-2.6.21.5/drivers/char/vt_ioctl.c 行1054
vt_waitactive函数里,vt== fg_console→正常返回。(fg_console为当前console的ID。)
NG流程:
bdh_dfb/systems/fbdev/vt.c 行167
↓
函数dfb_vt_initialize
while (ioctl( dfb_vt->fd0,VT_ACTIVATE, dfb_vt->num ) < 0) {
↓
kernel/linux-2.6.21.5/drivers/char/vt.c
执行LINUX Kernel的set_console函数
↓
ファイル:bdh_kernel/linux-2.6.21.5/drivers/char/vt.c行2208
函数schedule_console_callback
↓
ファイル: bdh_kernel/linux-2.6.21.5/drivers/char/vt.c 行2163
函数console_callback→执行change_console函数
↓
kernel/linux-2.6.21.5/drivers/char/vt_ioctl.c 行1220
函数complete_change_console没有被执行。 ★差别点
if (vc->vt_mode.mode == VT_PROCESS) {
/*
* Send the signal as privileged - kill_pid()will
* tell us if the process has gone or somethingelse
* is awry
*/
if(kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
/*
* It worked. Mark the vt to switch to and
* return. The process needs to send us a
* VT_RELDISP ioctl to complete the switch.
*/
vc->vt_newvt= new_vc->vc_num;
return; ★異常返回。
}
dfb/systems/fbdev/vt.c 行177
函数 dfb_vt_initialize
while (ioctl( dfb_vt->fd0,VT_WAITACTIVE, dfb_vt->num ) < 0) ↓
kernel/linux-2.6.21.5/drivers/char/vt_ioctl.c 行1054
vt_waitactive関数hangup。
总结:
对于这类系统性Bug,最好的分析方法还是做Log比对,分析差异点。
中间有两个难关: 1〉到底挂在哪个模块
2〉Linux内核为什么会被阻塞