linux 2.6 互斥鎖的實(shí)現(xiàn)-源碼分析

Linux 2.6 kernel的源碼茂契,下面結(jié)合代碼來分析一下在X86體系結(jié)構(gòu)下,互斥鎖的實(shí)現(xiàn)原理。

代碼分析:

1. 首先介紹一下互斥鎖所使用的數(shù)據(jù)結(jié)構(gòu):
struct mutex {
   atomic_t  count; //引用計數(shù)器,1: 所可以利用,小于等于0:該鎖已被獲取惭等,需要等待
   spinlock_t  wait_lock;//自旋鎖類型,保證多cpu下办铡,對等待隊列訪問是安全的辞做。
   spinlock_t  wait_lock; //等待隊列,如果該鎖被獲取寡具,任務(wù)將掛在此隊列上秤茅,等待調(diào)度。
   struct list_head wait_list;
};

2. 互斥鎖加鎖函數(shù)
void inline __sched mutex_lock(struct mutex *lock)

調(diào)用了宏:

__mutex_fastpath_lock(&lock->count, __mutex_lock_slowpath);

宏的定義:將mutex數(shù)據(jù)結(jié)構(gòu)中童叠,引用計數(shù)器減1框喳,如果不為負(fù)數(shù)就返回,如果為負(fù)數(shù)厦坛,需要調(diào)用函數(shù):__mutex_lock_slowpath五垮,接下來我們再來分析這個函數(shù),我們先來分析一下這個宏杜秸。

#define __mutex_fastpath_lock(count, fail_fn)  /
do {        /
   unsigned int dummy;    /
   //檢查參數(shù)類型的有效性
   typecheck(atomic_t *, count);    /
   typecheck_fn(void (*)(atomic_t *), fail_fn);  /
   //輸入放仗,輸出寄存器為eax,輸入為count,輸出為dummy,僅將eax的值減1
   asm volatile(LOCK_PREFIX "  decl (%%eax)/n"  /
   "  jns 1f /n"    /
  //如果減后為負(fù)數(shù),調(diào)用回調(diào)函數(shù)撬碟,嘗試阻塞該進(jìn)程
   "  call " #fail_fn "/n"  /
   "1:/n"    /
   : "=a" (dummy)    /
   : "a" (count)    /
   : "memory", "ecx", "edx");  /
} while (0)
3. 回調(diào)函數(shù)
static noinline int __sched __mutex_lock_killable_slowpath(atomic_t *lock_count)
{
//通過結(jié)構(gòu)的成員地址诞挨,獲取該結(jié)構(gòu)地址
   struct mutex *lock = container_of(lock_count, struct mutex, count);
//該函數(shù)在后面做詳細(xì)介紹
   return __mutex_lock_common(lock, TASK_KILLABLE, 0, _RET_IP_);
}
4. 阻塞進(jìn)程真正獲取鎖的地方
static inline int __sched
__mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,unsigned long ip)
{
   //獲取當(dāng)前進(jìn)程的task_struct的地址
   struct task_struct *task = current;
   struct mutex_waiter waiter;
   unsigned int old_val;
   unsigned long flags;

   //對該鎖上的等待隊列加自旋鎖,防止多個CPU的情況呢蛤。
   spin_lock_mutex(&lock->wait_lock, flags);

   //將該任務(wù)添加到該鎖的等待隊列上
   list_add_tail(&waiter.list, &lock->wait_list);
   waiter.task = task;

   //用一條匯編指令對count進(jìn)行付值惶傻,lock->count=-1,保證該操作在一個cpu上是原子的
   old_val = atomic_xchg(&lock->count, -1);

   //如果lock->count之前的值為1,說明是可以獲取鎖的
   if (old_val == 1)
       goto done;
   lock_contended(&lock->dep_map, ip);

   for (;;) {
       //在這個地方其障,又嘗試去獲取鎖达罗,處理方式如上。
       old_val = atomic_xchg(&lock->count, -1);
       if (old_val == 1)
           break;

       //如果該進(jìn)程是可中斷的静秆,或者該進(jìn)程是可kiilable的粮揉,如果有信號被遞送到該任務(wù),那么該進(jìn)程將從等待隊列中移除
       if (unlikely((state == TASK_INTERRUPTIBLE &&signal_pending(task)) ||(state == TASK_KILLABLE &&fatal_signal_pending(task)))) {
           mutex_remove_waiter(lock, &waiter,task_thread_info(task));
           mutex_release(&lock->dep_map, 1, ip);
           spin_unlock_mutex(&lock->wait_lock, flags);
           debug_mutex_free_waiter(&waiter);
           //返回被信號中斷
           return -EINTR;
       }
       __set_task_state(task, state);

       //如果還不能獲取所抚笔,則將自旋鎖解除扶认,當(dāng)從schedule返回時再次獲取自旋鎖,重復(fù)如上操作殊橙。
       spin_unlock_mutex(&lock->wait_lock, flags);
       schedule();
       spin_lock_mutex(&lock->wait_lock, flags);
   }
   //表示已經(jīng)獲取了鎖
   done:
   lock_acquired(&lock->dep_map);
   //將該任務(wù)從等待隊列中刪除
   mutex_remove_waiter(lock, &waiter, task_thread_info(task));
   debug_mutex_set_owner(lock, task_thread_info(task));
   //如果等待隊列為空將lock->count置為0
   if (likely(list_empty(&lock->wait_list)))
       atomic_set(&lock->count, 0);
   spin_unlock_mutex(&lock->wait_lock, flags);
   debug_mutex_free_waiter(&waiter);
   return 0;
}

5. 解鎖過程
void __sched mutex_unlock(struct mutex *lock)
{
   //解鎖后lock->count將從0變?yōu)?
   __mutex_fastpath_unlock(&lock->count,__mutex_unlock_slowpath);
}

//該宏是對引用計數(shù)器實(shí)行加1操作辐宾,如果加后小于等于0狱从,說明該等待隊列上還有任務(wù)需要獲取鎖。調(diào)用__mutex_unlock_slowpath函數(shù)叠纹。

#define __mutex_fastpath_unlock(count, fail_fn)  /
do {        /
   unsigned int dummy;    /
   /
   typecheck(atomic_t *, count);    /
   typecheck_fn(void (*)(atomic_t *), fail_fn);  /
   /
   asm volatile(LOCK_PREFIX "  incl (%%eax)/n"  /
       "  jg 1f/n"    /
       "  call " #fail_fn "/n"  /
       "1:/n"    /
       : "=a" (dummy)    /
       : "a" (count)    /
       : "memory", "ecx", "edx");  /
} while (0)

//該函數(shù)調(diào)用了__mutex_unlock_slowpath函數(shù)季研。

static noinline void
__mutex_unlock_slowpath(atomic_t *lock_count)
{
   __mutex_unlock_common_slowpath(lock_count, 1);
}
static inline void
__mutex_unlock_common_slowpath(atomic_t *lock_count, int nested)
{
   //通過結(jié)構(gòu)的成員地址,獲取該結(jié)構(gòu)地址
   struct mutex *lock = container_of(lock_count, struct mutex, count);

   unsigned long flags;
   //為等待隊列加自旋鎖
   spin_lock_mutex(&lock->wait_lock, flags);
   mutex_release(&lock->dep_map, nested, _RET_IP_);
   debug_mutex_unlock(lock);
   if (__mutex_slowpath_needs_to_unlock())
       atomic_set(&lock->count, 1);

   //先看看等待隊列是不是為空了誉察,如果已經(jīng)為空与涡,不需要做任何處理,否則將該等待隊列上面的隊首進(jìn)程喚醒
   if (!list_empty(&lock->wait_list)) {
       struct mutex_waiter *waiter =list_entry(lock->wait_list.next,struct mutex_waiter, list);
       debug_mutex_wake_waiter(lock, waiter);
       wake_up_process(waiter->task);
   }

   debug_mutex_clear_owner(lock);
   spin_unlock_mutex(&lock->wait_lock, flags);

}
總結(jié):

互斥鎖的實(shí)現(xiàn)持偏,實(shí)際上就是一把鎖維護(hù)了一個等待隊列和一個引用計數(shù)器驼卖,當(dāng)獲取鎖之前,先對引用計數(shù)器減1操作鸿秆,如果為非負(fù)酌畜,則可以獲取鎖進(jìn)入臨界區(qū)。否則需要將該任務(wù)掛在該等待對列上卿叽。

轉(zhuǎn)自:http://blog.csdn.net/tq02h2a/article/details/4317211

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末桥胞,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子考婴,更是在濱河造成了極大的恐慌埠戳,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蕉扮,死亡現(xiàn)場離奇詭異整胃,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來疏日,“玉大人独令,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長酬蹋。 經(jīng)常有香客問我,道長抽莱,這世上最難降的妖魔是什么范抓? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮食铐,結(jié)果婚禮上匕垫,老公的妹妹穿的比我還像新娘虐呻。我一直安慰自己寞秃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布春寿。 她就那樣靜靜地躺著,像睡著了一般忽孽。 火紅的嫁衣襯著肌膚如雪绑改。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機(jī)與錄音萤悴,去河邊找鬼。 笑死覆履,一個胖子當(dāng)著我的面吹牛蹋盆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播硝全,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼栖雾,長吁一口氣:“原來是場噩夢啊……” “哼伟众!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起凳厢,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎治泥,沒想到半個月后遮精,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體居夹,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡本冲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年檬洞,在試婚紗的時候發(fā)現(xiàn)自己被綠了意狠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疮胖。...
    茶點(diǎn)故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡闷板,死狀恐怖院塞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拦止,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布萧求,位于F島的核電站顶瞒,受9級特大地震影響夸政,放射性物質(zhì)發(fā)生泄漏榴徐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一坑资、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧仿便,春花似錦、人聲如沸探越。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽常柄。三九已至,卻和暖如春西潘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背喷市。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工品姓, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寝并,地道東北人。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓斤蔓,卻偏偏與公主長得像镀岛,于是被迫代替她去往敵國和親弦牡。 傳聞我的和親對象是個殘疾皇子漂羊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容