Linux驱动之自旋锁、读写自旋锁

自旋锁:

自旋锁实际上是一种忙等待,只有SMP或者支持抢占内核的系统支持。

另外需要注意的是,拥有自旋锁期间一定要避免休眠。原因是获得自旋锁时将抢占暂时关闭。一些copy_from_user、kmalloc等会导致休眠。

还有一种变体需要关闭中断,原因是中断发生时,中断服务函数有可能会获取一个自旋锁(这很有可能),而被中断的函数已经获得了这个自旋锁。这样中断服务函数只能自旋,而被中断的函数也没有机会释放自旋锁。

因此,一般的做法是,若是在中断上下文中(硬中断或者软中断)有机会使用自旋锁,则一定要使用某个禁止中断的自旋锁形式。若是只在软中断中访问自旋锁,则一定要使用spin_lock_bh,这样能防止死锁,同时又不需要禁止硬件中断。

A 定义:

typedef struct {
	raw_spinlock_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
} spinlock_t;
B 静态声明

DEFINE_SPINLOCK(i2c_lock);
i2c_lock = SPIN_LOCK_UNLOCKED;

C 动态声明

spinlock_t *lock;
spin_lock_init(lock);

D 获取、释放

spin_lock,spin_lock_irq,spin_lock_irqsave

spin_unlock, spin_unlock_irq, spin_unlock_irqsave

void __lockfunc _spin_lock(spinlock_t *lock)
{
	preempt_disable();
	spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
	LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
}
void __lockfunc _spin_lock_irq(spinlock_t *lock)
{
	local_irq_disable();
	preempt_disable();
	spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
	LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
}
上面可以看到preepmt_disable将抢占关闭。
#define spin_lock_irqsave(lock, flags)			\
	do {						\
		typecheck(unsigned long, flags);	\
		_spin_lock_irqsave(lock, flags);	\
	} while (0)
从中可以看出,自旋锁的获取和释放只是开启或者关闭抢占标志。

读写自旋锁:

读写自旋锁是为了一定程度上解决自旋锁浪费CPU资源问题。读操作可以并发,写操作是独占。

typedef struct {
	raw_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;

A,静态初始化

rwlock_t lock=RW_LOCK_UNLOCKED;

B,动态初始化

	rwlock_t *lock;
	rw_lock_init(lock);
C、读锁

read_lock read_unlock read_lock_irq read_lock_irqsave

void __lockfunc _read_lock(rwlock_t *lock)
{
	preempt_disable();
	rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
	LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
}
void __lockfunc _read_unlock(rwlock_t *lock)
{
	rwlock_release(&lock->dep_map, 1, _RET_IP_);
	_raw_read_unlock(lock);
	preempt_enable();
}
void __lockfunc _read_lock_irq(rwlock_t *lock)
{
	local_irq_disable();
	preempt_disable();
	rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
	LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
}
unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock)
{
	unsigned long flags;

	local_irq_save(flags);
	preempt_disable();
	rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
	LOCK_CONTENDED_FLAGS(lock, _raw_read_trylock, _raw_read_lock,
			     _raw_read_lock_flags, &flags);
	return flags;
}



D、写锁

write_lock write_unlock

void __lockfunc _write_lock(rwlock_t *lock)
{
	preempt_disable();
	rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
	LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock);
}

void __lockfunc _write_unlock(rwlock_t *lock)
{
	rwlock_release(&lock->dep_map, 1, _RET_IP_);
	_raw_write_unlock(lock);
	preempt_enable();
}

写饥饿:当有大量写操作时,写操作会自旋在写自旋上。因为读自旋锁能自由的获取,从而导致写自旋等待所有读自旋锁释放。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值