我自己制造了一个死锁:
static DEFINE_SPINLOCK(irq_button_lock); //定义并初始化一个自旋锁的实例 (就是定义一个结构体并对其中的某些成员进行赋值,这个宏的定义在include/linux/spinlock_types.h)
static void spinlock_test(void)
{
unsigned long spin_lock_flags;
spin_lock_irqsave(&irq_button_lock, spin_lock_flags); //申请锁
spin_lock_irqsave(&irq_button_lock, spin_lock_flags); //再次申请同一个锁,导致死锁
spin_unlock_irqrestore(&irq_button_lock, spin_lock_flags);
spin_unlock_irqrestore(&irq_button_lock, spin_lock_flags);
return;
}
实验发现,发生死锁后,手机会定屏,且不会响应用户的操作,只有连接trace32进行分析了。本以为这种情况下硬件的watch dog会被触发,但是却没有,不知什么原因。
分类: 操作系统/ Linux/ 文章
在多进程的的程序中不一定会死锁,因为多进程共享资源、相互通信的需要才有可能导致死锁。如果进程间老死不想往来,不可能因为等待资源而死锁,沟通需要成本,得到的可能是危机。不只是进程之间,当考虑中断与进程间的资源共享时,问题变得复杂起来。
自旋锁引起的死锁:
自旋锁不会引起调用者睡眠,如果一个执行线程试图获得一个已经被持有的自旋锁,那么线程就会一直进行忙循环,一直等待下去,直到自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。
自旋锁可能死锁的一般情况:
1 递归使用:
即在同一个进程中,申请了自旋锁,但是在没有释放之前又再次申请,这种情况必定死锁。
2 进程得到自旋锁后阻塞,睡眠:
在获得自旋锁之后调用copy_from_user()、copy_to_ser()、和kmalloc()等有可能引起阻塞的函数。
3 中断中没有关中断,或着因为申请未释放的自旋锁:
在中断中使用自旋锁是可以的,应该在进入中断的时候关闭中断,不然中断再次进入的时候,中断处理函数会自旋等待自旋锁可以再次使用。或者在进程中申请了自旋锁,释放前进入中断处理函数,中断处理函数又申请同样的自旋锁,这将导致死锁。
4 中断与中断下半部共享资源和中断与进程共享资源死锁出现的情况类似。
5 中断下半部与进程共享资源和中断与进程共享资源死锁出现的情况类似。
自旋锁三种状态:
自旋锁保持期间是抢占失效的(内核不允许被抢占)。
1 单CPU且内核不可抢占:
自旋锁的所有操作都是空。不会引起死锁,内核进程间不存在并发操作进程,进程与中断仍然可能共享数据,存在并发操作,此时内核自旋锁已经失去效果。
2 单CPU且内核可抢占:
当获得自旋锁的时候,禁止内核抢占直到释放锁为止。此时可能存在死锁的情况是参考自旋锁可能死锁的一般情况。
禁止内核抢占并不代表不会进行内核调度,如果在获得自旋锁后阻塞或者主动调度,内核会调度其他进程运行,被调度的内核进程返回用户空间时,会进行用户抢占,此时调用的进程再次申请上次未释放的自旋锁时,会一直自旋。但是内核被禁止抢占,从而造成死锁。
内核被禁止抢占,但此时中断并没被禁止,内核进程可能因为中断申请自旋锁而死锁。
3 多CPU且内核可抢占:
这才是是真正的SMP的情况。当获得自旋锁的时候,禁止内核抢占直到释放锁为止。