實際項目中的死鎖
下面的例子要復雜一些,這是從實際項目中抽取出來的死鎖,更具有代表性。
#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位,表示當前線程能進入掛起或休眠狀態(tài)。
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;
/*創(chuàng)建一個線程來處理某些事情*/
lock_thread = kthread_run(lockdep_thread, NULL, "lockdep_test");
/*創(chuàng)建一個延遲的工作隊列*/
INIT_DELAYED_WORK(&delay_task, lockdep_test_work);
/*創(chuàng)建一個定時器來模擬某些異步事件,如中斷等*/
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);
首先創(chuàng)建一個lockdep_thread內(nèi)核線程,用于周期性地處理某些事情,然后創(chuàng)建一個名為lockdep_test_worker的工作隊列來處理一些類似于中斷下半部的延遲操作,最后使用一個定時器來模擬某些異步事件(如中斷)。
在lockdep_thread內(nèi)核線程中,某些特殊情況下常常需要取消工作隊列。代碼中首先申請了一個mutex_a互斥鎖,然后調(diào)用cancel_delayed_work_sync()函數(shù)取消工作隊列。另外,定時器定時地調(diào)度工作隊列,并在回調(diào)函數(shù)lockdep_test_worker()函數(shù)中申請mutex_a互斥鎖。
接下來的函數(shù)調(diào)用棧顯示上述嘗試獲取mutex_a鎖的調(diào)用路徑。兩個路徑如下:
(1)內(nèi)核線程lockdep_thread首先成功獲取了mutex_a互斥鎖,然后調(diào)用cancel_delayed_work_sync()函數(shù)取消kworker。注意,cancel_delayed_work_sync()函數(shù)會調(diào)用flush操作并等待所有的kworker回調(diào)函數(shù)執(zhí)行完,然后才會調(diào)用mutex_unlock(&mutex_a)釋放該鎖。
(2)kworker回調(diào)函數(shù)lockdep_test_worker()首先會嘗試獲取mutex_a互斥鎖。 注意,剛才內(nèi)核線程lockdep_thread已經(jīng)獲取了mutex_a互斥鎖,并且一直在等待當前kworker回調(diào)函數(shù)執(zhí)行完,所以死鎖發(fā)生了 。
下面是該死鎖場景的CPU調(diào)用關系:
CPU0 CPU1
----------------------------------------------------------------
內(nèi)核線程lockdep_thread
lock(mutex_a)
cancel_delayed_work_sync()
等待worker執(zhí)行完成
delay worker回調(diào)函數(shù)
lock(mutex_a);嘗試獲取鎖
-
內(nèi)核
+關注
關注
3文章
1375瀏覽量
40312 -
Linux
+關注
關注
87文章
11314瀏覽量
209775 -
死鎖
+關注
關注
0文章
25瀏覽量
8079 -
函數(shù)
+關注
關注
3文章
4333瀏覽量
62720
發(fā)布評論請先 登錄
相關推薦
評論