您的位置:首页 > 运维架构 > Linux

Linux开发调试经验整理(一)——Release版本死锁定位

2015-09-09 21:55 609 查看
话说谁能生巧。以前由于经常被拉去定位疑难杂症,gdb用的还算熟练。最近年把因工作内容的调整,gdb很少用,前些日子定位问题时发现曾经很熟悉的东西都有点陌生了。因此决定把以前整理的一些小经验、技巧再回顾一下,并分享给大家。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

debug 版本的应用程序发生死锁,可以将pthread_mutex_t打印出来,查看其中的owner字段即可知道锁被哪个线程持有。

release版本的程序,由于进行了优化,可能无法直接打出锁变量。 这里介绍一个简单方法,可以查看release版(当然也支持debug)的锁状态,以便快速定位死锁问题。

操作步骤

1) gdb attach 到死锁的进程.

例如 gdb –p 2456

2) thread 命令切换到等待锁(这里主要指Mutex,暂不考虑读写锁)的某个线程。 可以结合 info thr、thr apply all bt 等命令确定哪些线程在等锁。

3) bt 查看该线程堆栈

(gdb) bt
#0 0x00110424 in __kernel_vsyscall ()
#1 0x0062d019 in __lll_lock_wait () from /lib/libpthread.so.0
#2 0x00628430 in _L_lock_677 () from /lib/libpthread.so.0
#3 0x00628301 in pthread_mutex_lock () from /lib/libpthread.so.0
……


4) frame 1 切换到 __lll_lock_wait () 帧

5) 执行 p (pthread_mutex_t)ebx1 = {__data = {__lock = 2, _count = 0, __owner = 20644, __kind = 0, __nusers = 1, {_spins = 0, __list = {

__next = 0x0}}},

__size = “\002\000\000\000\000\000\000\000\244P\000\000\000\000\000\000\001\000\000\000\000\000\000”, __align = 2}

Owner 字段表示是哪个线程持有这把锁,它是线程的 LWP 号,可以通过 info thr 查看。

6) 根据info thr 的信息,thr 命令切换到 owner对应的线程,结合代码排查。 一般来说,这个线程应该也在等锁,重复执行 4、5 步骤,可以看到它锁等待的锁被谁持有。 再结合代码分析,基本上可以定位出死锁位置。

注意事项

1)上述方法只适用于32bit系统上使用 pthread_mutex_t 造成的死锁。

X86_64 位系统上,对应的寄存器貌似是 rdi ,也就是说命令应该改成

p *(pthread_mutex_t)$rdi

2) 读写锁造成的死锁,需要结合glibc源码和汇编,找出pthread_rwlock_t的地址(具体是啥还有待分析 _),将其打印出来应该即可。

3)如果owner对应的线程已经退出,就无法通过gdb查看该线程的堆栈。 因此建议在日志中打印线程的LWP号(可通过getttid打印),找到该线程的日志信息,分析是哪个线程造成的死锁。

#define gettid() syscall(__NR_gettid)


4)如果提示 pthread_mutex_t 符号找不到,说明gdb没有为 pthreadtypes.h 加载符号表,这种情况下仍有方法查看锁状态

(gdb) print ((int)($ebx)) // lock 字段
$4 = 2
(gdb) print ((int)($ebx)+1) // count 字段
$5 = 0
print *((int)($ebx)+2) // owner字段*
$6 = 12275


附:pthread_mutex_t 定义

typedef union {
struct __pthread_mutex_s {
int lock;
unsigned int __count;
int __owner;
/* KIND must stay at this position in the structure to maintain
binary compatibility. */
int __kind;
unsigned int __nusers;
__extension union {
int _spins;
__pthread_slist_t __list;
};
} __data;
char __size[_SIZEOF_PTHREAD_MUTEX_T];
long int __align;
} pthread_mutex_t;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: