linux rwlock 读写锁实现

linux 内核中的rwlock类型的读写锁是基于spinlock来实现的。

读写锁具有如下特性:

  • 允许多个读者同时进入临界区,但同一时刻写者不能进入。
  • 同一时刻只允许一个写者进入临界区。
  • 读者和写者不能同时进入临界区。

1、spinlock类型读写锁

注意,spinlock类型读写锁,具有spinlock的特性及在lock时关闭内核抢占,在unlock时开启内核抢占。

include/linux/rwlock_types.h
/*spinlock实现的读写锁*/
typedef struct {
	arch_rwlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAK
	unsigned int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
	unsigned int magic, owner_cpu;
	void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
	struct lockdep_map dep_map;
#endif
} rwlock_t;

arch/arm/include/asm/spinlock_types.h
typedef struct {
	u32 lock;
} arch_rwlock_t;

#define __ARCH_RW_LOCK_UNLOCKED		{ 0 }

1.1、读写锁初始化

include/linux/rwlock.h

# define rwlock_init(lock) \

do { *(lock) = __RW_LOCK_UNLOCKED(lock); } while (0)


#define __RW_LOCK_UNLOCKED(lockname) \

(rwlock_t) { .raw_lock = __ARCH_RW_LOCK_UNLOCKED, \

RW_DEP_MAP_INIT(lockname) }


#define DEFINE_RWLOCK(x) rwlock_t x = __RW_LOCK_UNLOCKED(x)

1.2、读者自旋锁

1.2.1、read_lock

#define read_lock(lock)		_raw_read_lock(lock)
void __lockfunc _raw_read_lock(rwlock_t *lock)
{
	__raw_read_lock(lock);
}

static inline void __raw_read_lock(rwlock_t *lock)
{
	/*关闭内核抢占*/
	preempt_disable();
	rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
	/*do_raw_read_lock*/
	LOCK_CONTENDED(lock, do_raw_read_trylock, do_raw_read_lock);
}
# define do_raw_read_lock(rwlock)	do {__acquire(lock); arch_read_lock(&(rwlock)->raw_lock); } while (0)
/*
 * Read locks are a bit more hairy:
 *  - Exclusively load the lock value.
 *  - Increment it. (加一)
 *  - Store new lock value if positive(正数), and we still own this location.
 *    If the value is negative(负数), we've already failed.
 *  - If we failed to store the value, we want a negative result.
 *  - If we failed, try again.
 * Unlocking is similarly hairy.  We may have multiple read locks
 * currently active.  However, we know we won't have any write
 * locks.
 */
static inline void arch_read_lock(arch_rwlock_t *rw)
{
	unsigned long tmp, tmp2;

	prefetchw(&rw->lock);
	__asm__ __volatile__(
"1:	ldrex	%0, [%2]\n"		/*tmp = rw->lock*/
"	adds	%0, %0, #1\n"		/*tmp += 1,adds执行加法,更新cpsr寄存器中条件标志位(C,N,Z...)*/
"	strexpl	%1, %0, [%2]\n"		/*pl条件的含义:Plus,positive or zero,条件N == 0,即不为负数(>=0)条件才执行strex指令;tmp >= 0则rw->lock=tmp(原子地实现rw->lock++)*/
	WFE("mi")				/*MI条件的含义:Minus, negative,条件N == 1,即为负数(<0),说明tmp+=1后溢出或则写者抢先写入0x8000000,导致符号位为1;wfemi,cpu进入休眠*/
"	rsbpls	%0, %1, #0\n"		/*RSB(Reverse Subtraction):反向减法(tmp=0-tmp2),pl为条件位(tmp>=0),s为结果更新cpsr寄存器中条件标志位(C,N,Z...);tmp2=0,独占访问成功,tmp2=1,独占访问失败*/
"	bmi	1b"			/*负数条件下(独占访问失败)跳转到标签1处*/
	: "=&r" (tmp), "=&r" (tmp2)
	: "r" (&rw->lock)
	: "cc");

	smp_mb();
}

1.2.2、read_trylock

#define read_trylock(lock)	__cond_lock(lock, _raw_read_trylock(lock))
int __lockfunc _raw_read_trylock(rwlock_t *lock)
{
	return __raw_read_trylock(lock);
}
static inline int __raw_read_trylock(rwlock_t *lock)
{
	/*关闭内核抢占*/
	preempt_disable();
	if (do_raw_read_trylock(lock)) {
		rwlock_acquire_read(&lock->dep_map, 0, 1, _RET_IP_);
		return 1;
	}
	/*开启内核抢占*/
	preempt_enable();
	return 0;
}

# define do_raw_read_trylock(rwlock)	arch_read_trylock(&(rwlock)->raw_lock)

static inline int arch_read_trylock(arch_rwlock_t *rw)
{
	unsigned long contended, res;

	prefetchw(&rw->lock);
	do {
		__asm__ __volatile__(
		"	ldrex	%0, [%2]\n"		/*contended = rw->lock*/
		"	mov	%1, #0\n"			/*res = 0*/
		"	adds	%0, %0, #1\n"		/*contended += 1*/
		"	strexpl	%1, %0, [%2]"		/*注意pl的条件(contended>=0),rw->lock = contended*/
		: "=&r" (contended), "=&r" (res)
		: "r" (&rw->lock)
		: "cc");
	} while (res);

	/* If the lock is negative, then it is already held for write. */
	if (contended < 0x80000000) { /*获取锁成功返回1*/
		smp_mb();
		return 1;
	} else {
		return 0;
	}
}

1.2.3、read_unlock

#define read_unlock(lock)		_raw_read_unlock(lock)
void __lockfunc _raw_read_unlock(rwlock_t *lock)
{
	__raw_read_unlock(lock);
}
static inline void __raw_read_unlock(rwlock_t *lock)
{
	rwlock_release(&lock->dep_map, 1, _RET_IP_);
	do_raw_read_unlock(lock);
	/*开启内核抢占*/
	preempt_enable();
}

# define do_raw_read_unlock(rwlock)	do {arch_read_unlock(&(rwlock)->raw_lock); __release(lock); } while (0)

static inline void arch_read_unlock(arch_rwlock_t *rw)
{
	unsigned long tmp, tmp2;

	smp_mb();

	prefetchw(&rw->lock);
	__asm__ __volatile__(
"1:	ldrex	%0, [%2]\n"			/*tmp = rw->lock*/
"	sub	%0, %0, #1\n"			/*tmp -= 1*/
"	strex	%1, %0, [%2]\n"			/*w->lock = tmp*/
"	teq	%1, #0\n"				/*teq操作指的是测试相等性,它通过对两个操作数执行异或操作,并更新条件标志,但不保存结果.测试tmp2是否为0*/
"	bne	1b"				/*独占访问失败,跳转到标签1处*/
	: "=&r" (tmp), "=&r" (tmp2)
	: "r" (&rw->lock)
	: "cc");

	if (tmp == 0) /*tmp==0,表明所有的读者都释放了锁,通过sev唤醒写者(如果存在的话)*/
		dsb_sev();
}

1.3、写者自旋锁

1.3.1、write_lock

#define write_lock(lock)	_raw_write_lock(lock)
void __lockfunc _raw_write_lock(rwlock_t *lock)
{
	__raw_write_lock(lock);
}

include/linux/rwlock_api_smp.h
static inline void __raw_write_lock(rwlock_t *lock)
{
	/*关闭内核抢占*/
	preempt_disable();
	rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
	/*do_raw_write_lock*/
	LOCK_CONTENDED(lock, do_raw_write_trylock, do_raw_write_lock);
}

# define do_raw_write_lock(rwlock)	do {__acquire(lock); arch_write_lock(&(rwlock)->raw_lock); } while (0)

arch/arm/include/asm/spinlock.h
/*
 * RWLOCKS
 * Write locks are easy - we just set bit 31.  When unlocking, we can
 * just write zero since the lock is exclusively held(锁被独占).
 */

static inline void arch_write_lock(arch_rwlock_t *rw)
{
	unsigned long tmp;

	prefetchw(&rw->lock);
	__asm__ __volatile__(
"1:	ldrex	%0, [%1]\n"  		/*tmp=rw->lock*/
"	teq	%0, #0\n"		 	/*测试tmp是否为0*/
	WFE("ne")			 	/*tmp不为0,表示锁被其他任务持有,则CPU核进入睡眠状态*/
"	strexeq	%0, %2, [%1]\n" 		/*相等则rw->lock=0x80000000*/
"	teq	%0, #0\n"		 	/*测试tmp是否为0*/
"	bne	1b"			/*tmp不为0跳转到标签1处继续执行*/
	: "=&r" (tmp)
	: "r" (&rw->lock), "r" (0x80000000)
	: "cc");

	smp_mb();
}

1.3.2、write_trylock

#define write_trylock(lock)	__cond_lock(lock, _raw_write_trylock(lock))
int __lockfunc _raw_write_trylock(rwlock_t *lock)
{
	return __raw_write_trylock(lock);
}

static inline int __raw_write_trylock(rwlock_t *lock)
{
	preempt_disable();
	if (do_raw_write_trylock(lock)) {
		rwlock_acquire(&lock->dep_map, 0, 1, _RET_IP_);
		return 1;
	}
	preempt_enable();
	return 0;
}
# define do_raw_write_trylock(rwlock)	arch_write_trylock(&(rwlock)->raw_lock)

static inline int arch_write_trylock(arch_rwlock_t *rw)
{
	unsigned long contended, res;

	prefetchw(&rw->lock);
	do {
		__asm__ __volatile__(
		"	ldrex	%0, [%2]\n"			/*contended = rw->lock*/
		"	mov	%1, #0\n"				/*res = 0,除了独占访问失败需要尝试,其他情况如锁已被持有则返回0*/
		"	teq	%0, #0\n"				/*测试contended是否为0*/
		"	strexeq	%1, %3, [%2]"			/*contended为0的条件下(锁空闲),设置rw->lock=0x80000000表示写者持锁,设置失败res=1,需要继续尝试*/
		: "=&r" (contended), "=&r" (res)
		: "r" (&rw->lock), "r" (0x80000000)
		: "cc");
	} while (res); 		/*独占访问失败则继续尝试*/

	if (!contended) { 		/*获取锁成功返回1*/
		smp_mb();
		return 1;
	} else {			/*获取锁失败返回0*/
		return 0;
	}
}

1.3.3、write_unlock

#define write_unlock(lock)		_raw_write_unlock(lock)
void __lockfunc _raw_write_unlock(rwlock_t *lock)
{
	__raw_write_unlock(lock);
}
static inline void __raw_write_unlock(rwlock_t *lock)
{
	rwlock_release(&lock->dep_map, 1, _RET_IP_);
	do_raw_write_unlock(lock);
	/*开启内核抢占*/
	preempt_enable();
}
# define do_raw_write_unlock(rwlock)	do {arch_write_unlock(&(rwlock)->raw_lock); __release(lock); } while (0)

static inline void arch_write_unlock(arch_rwlock_t *rw)
{
	smp_mb();

	__asm__ __volatile__(
	"str	%1, [%0]\n"			/*rw->lock=0*/
	:
	: "r" (&rw->lock), "r" (0)
	: "cc");

	dsb_sev();					/*写者释放锁,唤醒其他休眠等待锁的读者/写者cpu*/
}

1.4、衍生的其他读写锁

read_lock_irq(lock) / read_unlock_irq(lock)
write_lock_irq(lock) / write_unlock_irq(lock)
read_lock_irqsave(lock, flags) / read_unlock_irqrestore(lock, flags)
write_lock_irqsave(lock, flags) / write_unlock_irqrestore(lock, flags)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值