某 x86 工控机在现场升级后无法正常连接,业务无法响应,工控机界面卡住。经较短时间分析并排查,解决了问题,虽然没有很难的技术问题,但过程还是值得记录的。
由于本文没有技术含量,请谨慎按需阅读。
起因
某天晚上近8点下班,骑电驴回家,路上,同事发了一个问题截图,现场反馈升级后机器卡住,无法正常工作。截图有pstack
输出的结果,初步看和我负责的一个模块有关,但看不出具体问题,后回复同事说明早看看。
排查及解决
问题定位
观察截图,进程有多个线程,涉及第三方厂家库,涉及Qt线程库、pthread线程库。信息较多,线索不好清理,但关键的问题,是找到问题的关键,本问题的关键在pthread_mutex_lock
、__lll_lock_wait
这2个关键字。——还好,这次不需要像年初那样找_gcry_ath_mutex_lock
、ath_mutex_t
关键字的源码。
根据关键字找到对应的模块代码,发现初始化和反初始化都用到了同一mutex
锁,从代码可以看到如初始化失败,会调用反初始化函数,由于反初始化函数也用了锁,但此时初始化未完成退出。因此,按初始化失败的流程走,是会锁住的。具体见下面的现场重演。
由于该模块一直能正常工作,本次升级的多台设备均未出现,从初始化失败的条件反推,有可能是所需要的外部文件出错。于是登陆设备,查看相关文件的md5,果然有料到,某一sqlite3数据库文件的md5与原版的不同,下载到本地后,用数据库工具打开,提示database disk image is malformed
。再用工具对比,错误文件的后半部分缺了,体积少了一半,但奇怪的是半部分是完全相同的,相当于被不可抗拒的力量裁为两截了。
因此,导致本次问题的原因是:升级过程中,数据库文件被破坏了,具体过程并不知晓,但无论怎么讲,知道原因后,解决就方便很多了。
解决方法
重新下载升级包进行升级即可。
现场重演
下面模拟实际工程的函数布局,舍去无关的代码,以突显问题。
注:将ret
改为负数即可重现问题。
/*
线程锁测试
编译命令:
g++ mutex_test.cpp -lpthread
*/#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>#include <pthread.h>static pthread_mutex_t module_lock = PTHREAD_MUTEX_INITIALIZER;void uninit()
{pthread_mutex_lock(&module_lock);printf("un init something.\n");pthread_mutex_unlock(&module_lock);
}void init()
{int ret = 0;printf("init start.\n");pthread_mutex_lock(&module_lock);// do something need and get return valueret = -1; // get wrong hereif (ret < 0) {uninit();}pthread_mutex_unlock(&module_lock);printf("init done.\n");
}int main(void)
{init();return 0;
}
在虚拟机的测试结果:
$ ./a.out
init start.
使用ps命令查看进程PID,再用pstack查看,结果如下:
$ ps aux | grep a.out
fengxuan 13971 0.0 0.0 14704 860 pts/2 S+ 09:50 0:00 ./a.out
fengxuan 13973 0.0 0.0 112828 996 pts/1 S+ 09:50 0:00 grep --color=auto a.out
$ pstack 13971
#0 0x00007f8389dd054d in __lll_lock_wait () from /lib64/libpthread.so.0
#1 0x00007f8389dcbe9b in _L_lock_883 () from /lib64/libpthread.so.0
#2 0x00007f8389dcbd68 in pthread_mutex_lock () from /lib64/libpthread.so.0
#3 0x000000000040062b in uninit() ()
#4 0x0000000000400676 in init() ()
#5 0x0000000000400695 in main ()
上述输出结果,和现场的不能说一模一样,只能说前3行的pthread库的函数一模一样。
小结
由于只一台设备出现问题,不具有代表性,但对于升级过程的文件完整性保证,还是需要做的。由于非个人范围,因此只是做了些建议。