新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > Linux同步機制自旋鎖原理及其應用

        Linux同步機制自旋鎖原理及其應用

        作者: 時間:2012-04-05 來源:網絡 收藏

        一、

        是專為防止多處理器并發而引入的一種鎖,它在內核中大量應用于中斷處理等部分(對于單處理器來說,防止中斷處理中的并發可簡單采用關閉中斷的方式,即在標志寄存器中關閉/打開中斷標志位,不需要)。

        自旋就是自己連續的循環等待。如果你有抱著你的愛人旋轉的經歷,那么你應該知道一件事情,為了安全,你不能旋轉太久,你的愛人如果頭昏,也想你早日釋放。是的,自旋的缺點,就是它頻繁的循環直到等待鎖的釋放,將它用于可以快速完成的代碼中才好。

        本文引用地址:http://www.104case.com/article/257593.htm

        自旋不能搶占,但能中斷。

        相關話題:SMP和cpu。多個cpu和單個cpu。很多書說自旋鎖只能在多處理機中使用,這是不正確的。
        首先定義
        Spinlock_t lock;
        對不起,我只能找到arm平臺的鎖了
        /*
        * ARMv6 Spin-locking.
        *
        * We (exclusively) read the old value, and decrement it. If it
        * hits zero, we may have won the lock, so we try (exclusively)
        * storing it.
        *
        * Unlocked value: 0
        * Locked value: 1
        */
        typedef struct {
        volatile unsigned int lock;
        #ifdef CONFIG_PREEMPT
        unsigned int break_lock;
        #endif
        } spinlock_t;
        補上x86平臺
        #define SPINLOCK_MAGIC 0x1D244B3C
        typedef struct {
        unsigned long magic;
        volatile unsigned long lock;
        volatile unsigned int babble;
        const char *module; // 所屬模塊
        char *owner;
        int oline;
        } spinlock_t;

        Lock為0時可以用,1是等待。0像鎖孔,當沒有鑰匙插進去時,它才可以插進去。

        怎么初始化呢?

        #define spin_lock_init(x)
        do {
        (x)->magic = SPINLOCK_MAGIC;
        (x)->lock = 0; ;0初始化,表示可用
        (x)->babble = 5;
        (x)->module = __FILE__;
        (x)->owner = NULL;
        (x)->oline = 0;
        } while (0)

        定義一個自旋鎖的方法很有意思,

        Spinlock_t lock=?????
        可以通過spin_lock
        Spin_lock_irqsave 來調用自旋鎖,后者不允許中斷。前者有可能在上鎖中發生中斷。
        還有spin_trylock 這是一個絕不妥協的函數,它不等待。

        恢復為spin_unlock
        Spin_unlock_irqrestore

        考查下面代碼
        #define spin_lock_irqsave(lock, flags) _spin_lock_irqsave(lock, flags)
        #define _spin_lock_irqsave(lock, flags)
        do {
        local_irq_save(flags); 保存中斷請求標志
        preempt_disable(); 不允許搶占
        _raw_spin_lock(lock);
        __acquire(lock);
        } while (0)

        二、自旋鎖綜合使用

        下面是一個使用的例子,你可以使用source insight查到它
        /* never called when PTRS_PER_PMD > 1 */
        void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused)
        {
        unsigned long flags; /* can be called from interrupt context */
        spin_lock_irqsave(pgd_lock, flags); 枷鎖
        pgd_list_del(pgd);
        spin_unlock_irqrestore(pgd_lock, flags); 釋放
        }
        中斷枷鎖
        #define spin_lock_irqsave(lock, flags) _spin_lock_irqsave(lock, flags)
        分析
        unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock)
        {
        unsigned long flags;
        local_irq_save(flags); 將寄存器存入flags,并關中斷
        preempt_disable(); 搶占鎖
        _raw_spin_lock_flags(lock, flags); 枷鎖
        return flags;
        }
        EXPORT_SYMBOL(_spin_lock_irqsave);
        繼續
        /* For spinlocks etc */
        #define local_irq_save(x) __asm__ __volatile__(pushfl ; popl %0 ; cli:=g (x): /* no input */ :memory)
        將標志寄存器的內容放在內存x中。請查看gcc匯編
        繼續
        static inline void _raw_spin_lock_flags (spinlock_t *lock, unsigned long flags)
        {
        #ifdef CONFIG_DEBUG_SPINLOCK
        if (unlikely(lock->magic != SPINLOCK_MAGIC)) {
        printk(eip: %p , __builtin_return_address(0));
        BUG();
        }
        #endif
        __asm__ __volatile__(
        spin_lock_string_flags
        :=m (lock->slock) : r (flags) : memory);
        }
        繼續
        #define spin_lock_string_flags
        1:
        lock ; decb %0 ;lock總線鎖住,原子操作
        jns 4f
        2:
        testl $0x200, %1
        jz 3f
        sti
        3:
        rep;nop
        cmpb $0, %0
        jle 3b
        cli
        jmp 1b
        4:
        理解一下大概意思,就可以了。當lock-1后大于等于0就可以關中斷繼續執行了,否則nop空操作。Nop期間,cpu可以執行其他任務的代碼。
        解鎖
        #define spin_unlock_irqrestore(lock, flags) _spin_unlock_irqrestore(lock, flags)
        void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
        {
        _raw_spin_unlock(lock);
        local_irq_restore(flags);
        preempt_enable();
        }
        static inline void _raw_spin_unlock(spinlock_t *lock)
        {
        #ifdef CONFIG_DEBUG_SPINLOCK
        BUG_ON(lock->magic != SPINLOCK_MAGIC);
        BUG_ON(!spin_is_locked(lock));
        #endif
        __asm__ __volatile__(
        spin_unlock_string
        );
        }
        Raw赤裸的解鎖,表示最低沉的解鎖原理。
        #define spin_unlock_string
        xchgb %b0, %1
        :=q (oldval), =m (lock->slock)
        :0 (oldval) : memory
        加1.解鎖

        linux操作系統文章專題:linux操作系統詳解(linux不再難懂)


        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 井研县| 花垣县| 曲靖市| 英超| 东方市| 桐乡市| 太康县| 葵青区| 黔南| 大同市| 闻喜县| 光泽县| 阳信县| 衡阳县| 汶川县| 疏勒县| 彭山县| 西林县| 广丰县| 徐州市| 白沙| 都江堰市| 九寨沟县| 石门县| 霸州市| 洛浦县| 连江县| 江孜县| 横峰县| 屏山县| 辛集市| 平舆县| 镇巴县| 广饶县| 长顺县| 丁青县| 桃园市| 廊坊市| 朔州市| 衡水市| 平山县|