• 单核与多核上锁的区别


    参考: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]      
    	"
        "   teq     %0, #0        
    	"
        "   strexeq %0, %2, [%1]  
    	"
        "   teqeq   %0, #0        
    	"
        "   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
    "
                    "sev"
            );
    }
     
    static inline void arch_spin_unlock(arch_spinlock_t *lock)                                                         
    {
            smp_mb();
    
            __asm__ __volatile__(
    "       str     %1, [%0]
    "
            :       
            : "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(); //与单核抢占情形相同
    }
  • 相关阅读:
    NETCF平台下利用XmlSerializer对于复杂类型序列化的探索(三)
    Hitachi H8/3687 芯片编程协议分析
    在PDA安装包中使用RAPI动态复制文件到设备
    程序员的程序不工作时他们最常说的20个回复
    推荐一个免费的建模工具JUDE Community
    混在博客园
    EpcGlobal XML Schema 文档
    NETCF平台下利用XmlSerializer对于复杂类型序列化的探索(二)
    NETCF平台下利用XmlSerializer对于复杂类型序列化的探索(一)
    尝试步行回家
  • 原文地址:https://www.cnblogs.com/openix/p/3301306.html
Copyright © 2020-2023  润新知