單核與多核上鎖的區別


參考:1、《Linux Kernel Development》3ed_CN  p131-p140

            2、2.6.34

單核:

//鎖的數據類型實現
typedef struct { } arch_spinlock_t;

typedef struct raw_spinlock {
    arch_spinlock_t raw_lock;
}raw_spinlock_t;

typedef struct spinlock {
    union {
        struct raw_spinlock rlock;
    }; //以我對C的了解,這種定義方式還是第一次見到(以前見到,也沒留意過),這個union的聯合體的最后竟然沒有變量名稱,即union {xxxxx} var_name; gcc后指定為c89標准也能正常編譯與運行
       //還有就是可以通過&lock->rlock,直接獲得訪問rlock的地址, 原來都是通過&lock->var_name.rlock來操作完成
       //此處加個變量名,反而顯得累贅,而且如果加上變量明就必須通過變量名訪問。 }spinlock_t;
//鎖是空的

 

 

//spin_lock的實現

#define __acquire(x) (void)0
#define __LOCK(lock) \
    do {preempt_disable(); __acquire(lock); (void)(lock); } while(0)
#define _raw_spin_lock(lock) __LOCK(lock)
#define raw_spin_lock(lock) _raw_spin_lock(lock)


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

//單核是否支持搶占在鎖上的區別:

#ifdef CONFIG_PREEMPT
#define preempt_disable() \
    do{ \
        inc_preempt_count(); \
        barrier(); \
    } while(0)
#else
#define preempt_disable() do { } while(0)

 

多核:

//鎖的數據類型實現
typedef struct {
    volatile unsigned int lock;
} arch_spinlock_t;

typedef struct raw_spinlock {
    arch_spinlock_t raw_lock;
} raw_spinlock_t;

typedef struct spinlock {
    union {
        struct raw_spinlock rlock;
    };
} spinlock_t;

 

//spin_lock的實現

static inline void arch_spin_lock(arch_spinlock_t *lock)
{
    unsigned long tmp;

    __asm__ __volatile__(
    "1: ldrex   %0, [%1]      \n\t"
    "   teq     %0, #0        \n\t"
    "   strexeq %0, %2, [%1]  \n\t"
    "   teqeq   %0, #0        \n\t"
    "   bne     1b                "
    : "=&r" (tmp)
    : "r" (&lock->lock), "r"(1)
    : "cc"
    smp_mb();
}

static inline void do_raw_spin_lock(raw_spinlock_t *lock)
{
    arch_spin_lock(&lock->raw_lock);
}

static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
    preempt_disable();
    do_raw_spin_lock(lock);
}

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

 

附:

1、同步,鎖的問題,我認為發生在(1)進程與進程之間;  (2)中斷與進程之間;  (3)中斷與中斷之間(細分上半部、下半部)

1)如果進程上下文核一個下半部共享數據,在訪問這些數據之前,需要禁止下半部的處理並得到鎖的使用權。做這些是為了本地和SMP的保護並且防止死鎖的出現。(p_128)

(2)如果中斷上下文和一個下半部共享數據,在訪問數據之前,需要禁止禁止中斷並得到鎖的使用權。做這些是為了本地和SMP的保護並且防止死鎖的出現。(p_128)

(3)如若在一段內核代碼操作某資源的時候系統產生了一個中斷,而該中斷的處理程序還要訪問這一個資源,這就是一個bug。(p_135最后)

    關於(3),經討論使用出使用spin_lock_irqsave;
    其它的也應有拌飯解決,以后會講明。

 

2、記下書中提出的幾條建議:

1)最開始設計的時候就要考慮加入鎖,而不是事后才想到。如果代碼已經寫好,再在其中找到需要上鎖的部分並向其中追加鎖,是非常困難的,結果也往往也不盡如人意。避免這種亡羊補牢的做法是:在編寫代碼的開始階段就要設計恰當的鎖。(p_136中間)

(2lock contention(鎖的爭用):是指當鎖正在被占用時,有其它線程試圖獲得該鎖。鎖處於高度爭用的狀態是指有多個其他線程在等待獲得該鎖。(p_138最后)

(3)被保護數據的規模描述了鎖的粒度,細粒度的鎖保護小塊數據,過粗的鎖保護大塊數據。(p_139中間)                       
    當鎖爭用嚴重時,加鎖太粗會降低可擴展性;而鎖爭用不明顯時,加鎖過細會加大系統開銷,帶來浪費,這兩種情況都會造成系統性能下降。(p_139最后)

 

還是談下spin_unlock,不然總缺了什么。

單核上:

static inline void spin_unlock(spinlock_t *lock)
{
        raw_spin_unlock(&lock->rlock);                                                                             
}

#define raw_spin_unlock(lock)           _raw_spin_unlock(lock)                                                     

#define _raw_spin_unlock(lock)                  __UNLOCK(lock)                                             

#define __UNLOCK(lock) \                                                                                           
  do { preempt_enable(); __release(lock); (void)(lock); } while (0)

#ifdef CONFIG_PREEMPT

#define preempt_enable_no_resched() \                                                                              
do { \
        barrier(); \
        dec_preempt_count(); \
} while (0)


#define preempt_check_resched() \                                                                                  
do { \
        if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \
                preempt_schedule(); \
} while (0)

//可能觸發內核態搶占
#define preempt_enable() \
do { \
        preempt_enable_no_resched(); \
        barrier(); \
        preempt_check_resched(); \
} while (0)    

#else

#define preempt_enable()                do { } while (0)                                                           

#endif                                                                                                    

 

 多核:

static inline void spin_unlock(spinlock_t *lock)
{
        raw_spin_unlock(&lock->rlock);                                                                             
}

#define raw_spin_unlock(lock)           _raw_spin_unlock(lock)                                                     

#define _raw_spin_unlock(lock) __raw_spin_unlock(lock)     

static inline void dsb_sev(void)                                                                                   
{
        __asm__ __volatile__ (
                "dsb\n"
                "sev"
        );
}
 
static inline void arch_spin_unlock(arch_spinlock_t *lock)                                                         
{
        smp_mb();

        __asm__ __volatile__(
"       str     %1, [%0]\n"
        :       
        : "r" (&lock->lock), "r" (0)
        : "cc");
                
        dsb_sev();
}       

void do_raw_spin_unlock(raw_spinlock_t *lock)                                                                      
{
//        debug_spin_unlock(lock);
        arch_spin_unlock(&lock->raw_lock);
}

static inline void __raw_spin_unlock(raw_spinlock_t *lock)                                                         
{
//        spin_release(&lock->dep_map, 1, _RET_IP_);
        do_raw_spin_unlock(lock);
        preempt_enable(); //與單核搶占情形相同
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM