参考资料:https://www.ibm.com/developerworks/cn/linux/l-cn-mcsspinlock/index.html
在qspinlock系列中使用了MCS,使用时仍使用spin_lock/spin_unlock、spin_lock_bh/spin_unlock_bh一套接口,对使用者透明。
mcs主要优化是将大部分自旋操作放在了per cpu的node中,防止多个cpu对同一个lock内存多次读写(全局的lock每次修改都会导致其他处理器缓存失效,频繁的缓存同步操作会导致繁重的系统总线和内存的流量,从而大大降低了系统整体的性能),以提高性能;通过链表实现了排队功能。
源码:
#define arch_spin_lock(l) queued_spin_lock(l)
#define arch_spin_unlock(l) queued_spin_unlock(l)
//spinlock
spinlock是一个atomic 类型的值,按bit分成如下几部分,在CPU个数不同时有所差别
/*
* Bitfields in the atomic value:
*
* When NR_CPUS < 16K
* 0- 7: locked byte
* 8: pending
* 9-15: not used
* 16-17: tail index
* 18-31: tail cpu (+1)
*
* When NR_CPUS >= 16K
* 0- 7: locked byte
* 8: pending
* 9-10: tail index
* 11-31: tail cpu (+1)
*/
/**
* queued_spin_lock - acquire a queued spinlock
* @lock: Pointer to queued spinlock structure
*/
static __always_inline void queued_spin_lock(struct qspinlock *lock)
{
u32 val;
/*尝试获取lock,获取成功直接return, 否则进入queued_spin_lock_slowpath排队获取lock*/
val = atomic_cmpxchg_acquire(&lock->val, 0, _Q_LOCKED_VAL);
if (likely(val == 0))
return;
queued_spin_lock_slowpath(lock, val);
}
/**
* queued_spin_lock_slowpath - acquire the queued spinlock
* @lock: Pointer to queued spinlock structure
* @val: Current value of the queued spinlock 32-bit word
*
* (queue tail, pending bit, lock value)
*
* fast : slow : unlock
* : :
* uncontended (0,0,0) -:--> (0,0,1) ------------------------------:--> (*,*,0)
* : | ^--------.------. / :
* : v \ \ | :
* pending : (0,1,1) +--> (0,1,0) \ | :
* : | ^--' | | :
* : v | | :
* uncontended