问题描述:pthread_mutex_lock时必现设备卡住问题
平台:君正MIPS x1500嵌入式linux平台
背景:两个进程之间通信需要做互斥操作,我在共享内存区域创建了一个共享锁结构,结果在使用过程中出现上述问题
排查过程:首先通过demo程序排除了锁资源不可用导致等待的因素,对调用接口进行反复功能测试,排除功能问题。将共享锁换成进程内部全局锁,没有问题。
1)对比两把锁的两个区别,1、作用域 2、共享结构体;将进程内部全局锁封装成跟共享锁相同的结构体,问题复现,得出初步结论:跟内存类型无关,跟锁所在结构有关。
2)将结构体成员位置调整,发现当pthread_mutex_t变量的起始地址为4的整数倍时,不会出现卡住现象,否则会出现卡住问题。然后发现结构体所在源文件包含了paramLib.h,该头文件定义了单字节内存对齐
3)得出结论:内存未四字节对齐会导致系统互斥锁调用卡住死锁。
4)延伸结论:不可以在约定单字节对齐的前提下重新定义包含系统复杂结构的变量成员的结构,会导致复杂结构成员内存分布与大小与系统内部有出入,调用时不匹配,从而导致诸如系统卡住死锁等严重系统问题
5)这个问题网上记录很少甚至没有,有一句规定:“系统对基本数据类型的首地址有字节对齐的要求(一般都是4字节对齐)”,这里的基本数据类型应该不包含pthread.h中定义的pthread_mutex_t,但是查看内核中该结构体的定义:
typedef union
{
struct __pthread_mutex_s
{
int __lock;
unsigned int __count;
int __owner;
#if __WORDSIZE == 64
unsigned int __nusers;
#endif
/* KIND must stay at this position in the structure to maintain
binary compatibility. */
int __kind;
#if __WORDSIZE == 64
int __spins;
__pthread_list_t __list;
# define __PTHREAD_MUTEX_HAVE_PREV 1
#else
unsigned int __nusers;
__extension__ union
{
int __spins;
__pthread_slist_t __list;
};
#endif
} __data;
char __size[__SIZEOF_PTHREAD_MUTEX_T];
long int __align;
} pthread_mutex_t;
该结构体中包含int、char等基本数据类型,且结构体的首地址就是结构体第一个int成员的首地址,如果所在地址(此处泛指MMU转换后的虚拟地址)不是4的整数倍,将会出现不可预知的问题(具体会发生什么现象没有明确说明,我这边是进程卡住而非某个调用线程卡住,说明对系统本身造成了影响)。
这个案例在实际应用调试过程中很有参考价值,因为问题发生时不会进程退出或系统重启,给调试带来困难。此外,对于怀疑有一些恶意代码攻击提供了一个首要排查方向(锁的实现机制一般都在内核层,影响受众多)。