super皮波 发表于 2014-07-04 16:24

请教一下自旋锁实现的问题

不好意思,身上实在是没分了,以后再补吧
体系结构arm,内核版本3.10.17,以下这段代码是arm中自旋锁的实现,网上资料太少了,实在没看懂这里是如何实现自旋锁的功能的
请懂的朋友帮帮忙,分确实少了,以后赚了分再给您,多谢

最好可以帮忙解释一下这段代码
static inline void arch_spin_lock(arch_spinlock_t *lock)
{
        unsigned long tmp;
        u32 newval;
        arch_spinlock_t lockval;

        __asm__ __volatile__(
"1:        ldrex        %0, [%3]\n"
"        add        %1, %0, %4\n"
"        strex        %2, %1, [%3]\n"
"        teq        %2, #0\n"
"        bne        1b"
        : "=&r" (lockval), "=&r" (newval), "=&r" (tmp)
        : "r" (&lock->slock), "I" (1 << TICKET_SHIFT)
        : "cc");

        while (lockval.tickets.next != lockval.tickets.owner) {/*目测这里是在自旋忙等,可是这里使用的判断条件和上面没有关系啊*/
                wfe();
                lockval.tickets.owner = ACCESS_ONCE(lock->tickets.owner);
        }

        smp_mb();
}

arm-linux-gcc 发表于 2014-07-04 16:24

本帖最后由 arm-linux-gcc 于 2014-07-04 17:19 编辑

typedef struct {
        union {
                u32 slock;
                struct __raw_tickets {
#ifdef __ARMEB__
                        u16 next;
                        u16 owner;
#else
                        u16 owner;
                        u16 next;
#endif
                } tickets;
        };
} arch_spinlock_t;

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

        __asm__ __volatile__(
"1:        ldrex        %0, [%3]\n"                                          
"        add        %1, %0, %4\n"                                    对next++
"        strex        %2, %1, [%3]\n"                           
"        teq        %2, #0\n"
"        bne        1b"
        : "=&r" (lockval), "=&r" (newval), "=&r" (tmp)
        : "r" (&lock->slock), "I" (1 << TICKET_SHIFT)
        : "cc");

        while (lockval.tickets.next != lockval.tickets.owner) {
                wfe();
                lockval.tickets.owner = ACCESS_ONCE(lock->tickets.owner);         
        }

        smp_mb();
}

static inline void arch_spin_unlock(arch_spinlock_t *lock)
{
        smp_mb();
        lock->tickets.owner++;             对owner++
        dsb_sev();                              
}

释放锁就会让owner++
持有锁就会让next++
用两个计数器分别来表示“释放次数”和“加锁次数”
当owner和next数量相等时,才说明当前线程成功的持有了锁

用两个计数器是出于性能考虑,这样就可以保证不同的cpu core不用竞争同一个地址,原因:
在arch_spin_lock里面使用了一个局部变量,于是不同执行流中的arch_spin_lock/arch_spin_unlock就不会写同一个cache line,
也就是不需要与别的core上的arch_spin_lock/arch_spin_unlock流程去竞争同一个cache line,
避免了两个core相互将对方的cache line write invalid的问题,于是就避免了cache miss的问题,从而保证了性能









asuka2001 发表于 2014-07-04 16:27

回复 1# super皮波

请自行搜索ticket spinlocks @lwn.net

arm-linux-gcc 发表于 2014-07-04 17:14

可用积分到底是用来干嘛的啊?

super皮波 发表于 2014-07-04 17:17

我感觉最大的用处就是可以参加竞拍
回复 4# arm-linux-gcc


   

super皮波 发表于 2014-07-04 17:18

兄弟,多谢了,按照你的回帖在网上找了下资料,弄明白了,再次感谢
回复 3# asuka2001


   

asuka2001 发表于 2014-07-04 17:44

本帖最后由 asuka2001 于 2014-07-04 17:50 编辑

回复 2# arm-linux-gcc

两个计数器理解为:下一个人的“排队号”和当前的“呼叫号”更为确切些。

竞争锁就是去取这个排队号,然后把这个号原子性加1,防止其他人拿到和自己相同的排队号,然后坐等释放锁的人呼叫自己的排队号既可!

释放锁时将呼叫号加1,即当前持有锁的人已经服务完了,呼叫下一位排队等待的兄弟来拿锁!
页: [1]
查看完整版本: 请教一下自旋锁实现的问题