6.3 Linux內(nèi)核自旋鎖

  • Spinlock 是內(nèi)核中提供的一種比較常見的鎖機(jī)制,自旋鎖是“原地等待”的方式解決資源沖突的,即恤筛,一個線程獲取了一個自旋鎖后芹橡,另外一個線程期望獲取該自旋鎖毒坛,獲取不到,只能夠原地“打轉(zhuǎn)”(忙等待)林说。由于自旋鎖的這個忙等待的特性,注定了它使用場景上的限制 —— 自旋鎖不應(yīng)該被長時間的持有(消耗 CPU 資源)腿箩。
  • 為了避免因為調(diào)度可能自旋的線程而浪費CPU豪直,可以嘗試獲取從運行隊列移出的其他線程持有的鎖,只要持有自旋鎖的代碼正在運行度秘,內(nèi)核就會禁止搶占顶伞。禁止搶占可以防止自旋鎖持有者被移出運行隊列饵撑,這會導(dǎo)致等待進(jìn)程長時間自旋而消耗CPU剑梳。
  • 只要有一個任務(wù)持有自旋鎖,其他任務(wù)就可能在等待的時候自旋滑潘。用自旋鎖時垢乙,必須確保不會長時間持有它∮锫保可能有人會說在循環(huán)中自旋所浪費CPU時間,比線程進(jìn)入睡眠粹舵,上下文切換到其他線程或進(jìn)程,然后再喚醒所浪費的CPU更好一些巴席。在一個處理器上自旋意味著在該處理器上不能再運行其他任何任務(wù)漾唉;在單核機(jī)器上使用自旋鎖是沒有任何意義的赵刑。最佳情況下场刑,系統(tǒng)可能會變慢,最糟情況下屎勘,和互斥鎖一樣會造成死鎖概漱。正是因為這個原因瓤摧,內(nèi)核在處理單個處理器上的spin_lock(spinlock_t *lock)調(diào)用時將禁止搶占照弥。在單個處理器(核)系統(tǒng)上这揣,應(yīng)該使用spin_lock_irqsave()和spin_unlock_ irqrestore()给赞,它們分別禁用處理器上中斷片迅,防止中斷并發(fā)皆辽。
  • 由于事先并不知道所寫驅(qū)動程序運行在什么系統(tǒng)上柑蛇,因此建議使用spin_lock_irqsave (spinlock_t *lock, unsigned long flags)獲取自旋鎖,該函數(shù)會在獲取自旋鎖之前驱闷,禁止當(dāng)前處理器(調(diào)用該函數(shù)的處理器)上中斷耻台。spin_lock_irqsave在內(nèi)部調(diào)用local_irq_save (flags)和preempt_disable(),前者是一個依賴于體系結(jié)構(gòu)的函數(shù)空另,用于保存IRQ狀態(tài)盆耽,后者禁止在相關(guān)CPU上發(fā)生搶占。然后應(yīng)該用spin_unlock_irqrestore()釋放鎖痹换,它執(zhí)行的操作與我們前面列舉的相反征字。

自旋鎖的特點

1.當(dāng)發(fā)生訪問資源沖突的時候,可以有兩個選擇:一個是死等娇豫,一個是掛起當(dāng)前進(jìn)程匙姜,調(diào)度其他進(jìn)程執(zhí)行。spin lock是一種死等的機(jī)制.
2.只允許一個thread進(jìn)入冯痢。semaphore可以允許多個thread進(jìn)入氮昧,spin lock不行框杜,一次只能有一個thread獲取鎖并進(jìn)入臨界區(qū),其他的thread都是在門口不斷的嘗試袖肥。
3.臨界區(qū)執(zhí)行時間要短咪辱,臨界區(qū)執(zhí)行時間過長,等待該自旋鎖空等的時間越長椎组,浪費CPU資源油狂。
4.可以在中斷上下文執(zhí)行。由于不睡眠寸癌,因此spin lock可以在中斷上下文中適用专筷。

自旋鎖的定義

struct liblockdep_pthread_mutex {
    pthread_mutex_t mutex;
    struct lock_class_key key;
    struct lockdep_map dep_map;
};

typedef struct liblockdep_pthread_mutex liblockdep_pthread_mutex_t;
#define pthread_mutex_t         liblockdep_pthread_mutex_t
#define spinlock_t      pthread_mutex_t

static __always_inline void spin_lock(spinlock_t *lock)
{
    raw_spin_lock(&lock->rlock);
}

spin_lock的調(diào)用關(guān)系
spin_lock
|
+ -----> raw_spin_lock
|
+------> _raw_spin_lock
|
+--------> __raw_spin_lock

static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
    preempt_disable();
    spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
    LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}

spin_lock_irq的調(diào)用關(guān)系
spin_lock_irq
|
+ -----> raw_spin_lock_irq
|
+------> _raw_spin_lock_irq
|
+--------> __raw_spin_lock_irq

static inline void __raw_spin_lock_irq(raw_spinlock_t *lock)
{
    local_irq_disable();
    preempt_disable();
    spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
    LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}

spin_trylock最終調(diào)用的是__raw_spin_trylock,成功返回1蒸苇,獲取失敗返回0

static inline int __raw_spin_trylock(raw_spinlock_t *lock)
{
    preempt_disable();
    if (do_raw_spin_trylock(lock)) {
        spin_acquire(&lock->dep_map, 0, 1, _RET_IP_);
        return 1;
    }
    preempt_enable();
    return 0;
}

自旋鎖的使用

1 定義自旋鎖變量 spinlock_t testlock磷蛹;

2 初始化鎖 spin_lock_init(&testlock);

以上兩步也可以通過DEFINE_SPINLOCK(testlock)來實現(xiàn)

3 獲取鎖 spin_lock/spin_lock_irq/spin_lock_irqsave

4 釋放鎖 spin_unlock/spin_unlock_irq/spin_unlock_restore

實例

drivers/input/keyboard/gpio_keys.c

struct gpio_button_data {
        ......
    spinlock_t lock;
        ......
};

spin_lock_init(&bdata->lock);

static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
{
    struct gpio_button_data *bdata = dev_id;
    struct input_dev *input = bdata->input;
    unsigned long flags;

    BUG_ON(irq != bdata->irq);

    spin_lock_irqsave(&bdata->lock, flags);

    if (!bdata->key_pressed) {
        if (bdata->button->wakeup)
            pm_wakeup_event(bdata->input->dev.parent, 0);

        input_event(input, EV_KEY, *bdata->code, 1);
        input_sync(input);

        if (!bdata->release_delay) {
            input_event(input, EV_KEY, *bdata->code, 0);
            input_sync(input);
            goto out;
        }

        bdata->key_pressed = true;
    }

    if (bdata->release_delay)
        hrtimer_start(&bdata->release_timer,
                  ms_to_ktime(bdata->release_delay),
                  HRTIMER_MODE_REL_HARD);
out:
    spin_unlock_irqrestore(&bdata->lock, flags);
    return IRQ_HANDLED;
}

drivers/cpuidle/cpuidle-ux500.c

void nv50_crc_handle_vblank(struct nv50_head *head)
{
        ......
    /*
     * We don't lose events if we aren't able to report CRCs until the
     * next vblank, so only report CRCs if the locks we need aren't
     * contended to prevent missing an actual vblank event
     */
    if (!spin_trylock(&crc->lock))
        return;

    if (!crc->src)
        goto out;

  out:
    spin_unlock(&crc->lock);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末溪烤,一起剝皮案震驚了整個濱河市味咳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌檬嘀,老刑警劉巖槽驶,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異枪眉,居然都是意外死亡捺檬,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門贸铜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人聂受,你說我怎么就攤上這事蒿秦。” “怎么了蛋济?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵棍鳖,是天一觀的道長。 經(jīng)常有香客問我碗旅,道長渡处,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任祟辟,我火速辦了婚禮医瘫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘旧困。我一直安慰自己醇份,他們只是感情好稼锅,可當(dāng)我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著僚纷,像睡著了一般矩距。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上怖竭,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天锥债,我揣著相機(jī)與錄音,去河邊找鬼痊臭。 笑死赞弥,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的趣兄。 我是一名探鬼主播绽左,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼艇潭!你這毒婦竟也來了拼窥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤蹋凝,失蹤者是張志新(化名)和其女友劉穎鲁纠,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鳍寂,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡改含,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了迄汛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捍壤。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖鞍爱,靈堂內(nèi)的尸體忽然破棺而出鹃觉,到底是詐尸還是另有隱情,我是刑警寧澤睹逃,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布盗扇,位于F島的核電站,受9級特大地震影響沉填,放射性物質(zhì)發(fā)生泄漏疗隶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一翼闹、第九天 我趴在偏房一處隱蔽的房頂上張望斑鼻。 院中可真熱鬧,春花似錦橄碾、人聲如沸卵沉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽史汗。三九已至琼掠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間停撞,已是汗流浹背瓷蛙。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留戈毒,地道東北人艰猬。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像埋市,于是被迫代替她去往敵國和親冠桃。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,665評論 2 354

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