实际项目中的死锁
下面的例子要复杂一些,这是从实际项目中抽取出来的死锁,更具有代表性。
#include < linux/init.h >
#include < linux/module.h >
#include < linux/kernel.h >
#include < linux/kthread.h >
#include < linux/freezer.h >
#include < linux/delay.h >
static DEFINE_MUTEX(mutex_a);
static struct delayed_work delay_task;
static void lockdep_timefunc(unsigned long);
static DEFINE_TIMER(lockdep_timer, lockdep_timefunc, 0, 0);
static void lockdep_timefunc(unsigned long dummy)
{
schedule_delayed_work(&delay_task, 10);
mod_timer(&lockdep_timer, jiffies + msecs_to_jiffies(100));
}
static void lockdep_test_work(struct work_struct *work)
{
mutex_lock(&mutex_a);
mdelay(300);//处理一些事情,这里用mdelay替代
mutex_unlock(&mutex_a);
}
static int lockdep_thread(void *nothing)
{
set_freezable();//清除当前线程标志flags中的PF_NOFREEZE位,表示当前线程能进入挂起或休眠状态。
set_user_nice(current, 0);
while(!kthread_should_stop()){
mdelay(500);//处理一些事情,这里用mdelay替代
//遇到某些特殊情况,需要取消delay_task
mutex_lock(&mutex_a);
cancel_delayed_work_sync(&delay_task);
mutex_unlock(&mutex_a);
}
return 0;
}
static int __init lockdep_test_init(void)
{
printk("figo:my lockdep module initn");
struct task_struct *lock_thread;
/*创建一个线程来处理某些事情*/
lock_thread = kthread_run(lockdep_thread, NULL, "lockdep_test");
/*创建一个延迟的工作队列*/
INIT_DELAYED_WORK(&delay_task, lockdep_test_work);
/*创建一个定时器来模拟某些异步事件,如中断等*/
lockdep_timer.expires = jiffies + msecs_to_jiffies(500);
add_timer(&lockdep_timer);
return 0;
}
static void __exit lockdep_test_exit(void)
{
printk("goodbyen");
}
MODULE_LICENSE("GPL");
module_init(lockdep_test_init);
module_exit(lockdep_test_exit);
首先创建一个lockdep_thread内核线程,用于周期性地处理某些事情,然后创建一个名为lockdep_test_worker的工作队列来处理一些类似于中断下半部的延迟操作,最后使用一个定时器来模拟某些异步事件(如中断)。
在lockdep_thread内核线程中,某些特殊情况下常常需要取消工作队列。代码中首先申请了一个mutex_a互斥锁,然后调用cancel_delayed_work_sync()函数取消工作队列。另外,定时器定时地调度工作队列,并在回调函数lockdep_test_worker()函数中申请mutex_a互斥锁。
接下来的函数调用栈显示上述尝试获取mutex_a锁的调用路径。两个路径如下:
(1)内核线程lockdep_thread首先成功获取了mutex_a互斥锁,然后调用cancel_delayed_work_sync()函数取消kworker。注意,cancel_delayed_work_sync()函数会调用flush操作并等待所有的kworker回调函数执行完,然后才会调用mutex_unlock(&mutex_a)释放该锁。
(2)kworker回调函数lockdep_test_worker()首先会尝试获取mutex_a互斥锁。 注意,刚才内核线程lockdep_thread已经获取了mutex_a互斥锁,并且一直在等待当前kworker回调函数执行完,所以死锁发生了 。
下面是该死锁场景的CPU调用关系:
CPU0 CPU1
----------------------------------------------------------------
内核线程lockdep_thread
lock(mutex_a)
cancel_delayed_work_sync()
等待worker执行完成
delay worker回调函数
lock(mutex_a);尝试获取锁
-
内核
+关注
关注
3文章
1363浏览量
40228 -
Linux
+关注
关注
87文章
11225浏览量
208920 -
死锁
+关注
关注
0文章
25浏览量
8066 -
函数
+关注
关注
3文章
4304浏览量
62428
发布评论请先 登录
相关推荐
评论