忆疑难问题定位及解决一

问题描述:版本a压力测试中出现线程丢失,但是进程还在,某些进程出现死锁,出现频率随机。由于该问题的存在,a版本没有发布,如果无法定位解决以后的版本都无法发布,所以在下一个版本b中,我被分配重点解决该问题。


基本思路:

1、查看新增代码,由于版本a新增代码量并不大,并且出现问题需要几天甚至十几天时间,所以比对代码可能是最直接的方法。但是详细查看新增代码,反复多遍,找到一些怀疑点,比如inet_ntoa,该函数不是线程安全函数,它内部使用局部变量存储转换后的字符串,在多线程环境下有安全隐患,将其替换为线程安全函数inet_ntop,压力下仍会出现问题。所以直接从代码上定位没有进一步的进展。


2、使用gdb远程调试,在查看代码的同时,还进行着这项操作,该问题难以定位的原因是,线程丢失但是进程没有崩溃,没有core文件可供分析,并且日志上也没有异常信息,似乎无从下手,所以考虑使用gdb attach 该线程,这样一来,当该线程即将退出的时刻,操作系统抛出的异常信号,会被gdb捕获,而当时的堆栈信息也会被保存下来,查看堆栈信息就能定位到问题。所以网上找了gdbserver的源码交叉编译为powerpc平台下的文件,但是只要attach该线程,问题就无法出现。所以最后放弃使用这个方法。


3.分析core文件,版本a出现问题时,分析dunp下来的core文件,查到了丢失线程,并且丢失的线程占用了sip锁,造成了其他线程的死锁,但是至于代码是执行到哪里退出的代码范围太大,曾经也想过在暂用该锁之后的代码中增加打印,但是定位的范围还是太大,最终没有使用。


4、最终是在全部分析代码,结合版本b出问题是的core文件,找到了线索。版本b出现问题是丢失了另一个线程,查看该线程各个地方,发现暂用sip锁的只有一处,由于没有该线程的堆栈,所以只能查看全部变量来分析,当时将所有通道的结构体变量print出来,逐个分析状态和变量值,大致定位了一个可疑代码段。然后我增加了一个全部的变量记录行号,用这个变量加在可疑代码的上下,这样如果下次出现问题的时候就能查看这个变量,来具体定位问题代码了。而且这招果然帮助我们定位到了问题,让人万万没有想到的是,出现的问题的代码居然是一句ioctl。继续向下追踪,也是在多次的怀疑,否定后定位到原因,是由于ioctl在驱动代码中,从内核态向用户态拷贝数据没有使用copy_to_user,而是直接将数据写到上次传下来的地址中。修改,测试后问题得到了验证和解决。

你可能感兴趣的:(忆疑难问题定位及解决一)