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