DIY编程器网

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 803|回复: 0
打印 上一主题 下一主题

[待整理] Linux同步机制自旋锁原理及其应用

[复制链接]
跳转到指定楼层
楼主
发表于 2014-10-11 01:42:11 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一、自旋锁

自旋锁是专为防止多处理器并发而引入的一种锁,它在内核中大量应用于中断处理等部分(对于单处理器来说,防止中断处理中的并发可简单采用关闭中断的方式,即在标志寄存器中关闭/打开中断标志位,不需要自旋锁)。

自旋就是自己连续的循环等待。如果你有抱着你的爱人旋转的经历,那么你应该知道一件事情,为了安全,你不能旋转太久,你的爱人如果头昏,也想你早日释放。是的,自旋的缺点,就是它频繁的循环直到等待锁的释放,将它用于可以快速完成的代码中才好。
自旋不能抢占,但能中断。

相关话题:SMP和cpu。多个cpu和单个cpu。很多书说自旋锁只能在多处理机中使用,这是不正确的。
首先定义
Spinlock_t lock;
对不起,我只能找到arm平台的锁了
/*
* ARMv6 Spin-locking.
*
* We (exclusively) read the old value, and decrement it.  If it
* hits zero, we may have won the lock, so we try (exclusively)
* storing it.
*
* Unlocked value: 0
* Locked value: 1
*/
typedef struct {
volatile unsigned int lock;
#ifdef CONFIG_PREEMPT
unsigned int break_lock;
#endif
} spinlock_t;
补上x86平台
#define SPINLOCK_MAGIC 0x1D244B3C
typedef struct {
unsigned long magic;
volatile unsigned long lock;
volatile unsigned int babble;
const char *module;    // 所属模块
char *owner;
int oline;
} spinlock_t;

Lock为0时可以用,1是等待。0像锁孔,当没有钥匙插进去时,它才可以插进去。
怎么初始化呢?

#define spin_lock_init(x)
do {
(x)->magic = SPINLOCK_MAGIC;
(x)->lock = 0;                ;0初始化,表示可用
(x)->babble = 5;
(x)->module = __FILE__;      
(x)->owner = NULL;
(x)->oline = 0;
} while (0)

定义一个自旋锁的方法很有意思,

Spinlock_t lock=?????
可以通过spin_lock
Spin_lock_irqsave 来调用自旋锁,后者不允许中断。前者有可能在上锁中发生中断。
还有spin_trylock 这是一个绝不妥协的函数,它不等待。
恢复为spin_unlock
Spin_unlock_irqrestore

考查下面代码
#define spin_lock_irqsave(lock, flags) _spin_lock_irqsave(lock, flags)
#define _spin_lock_irqsave(lock, flags)
do {
local_irq_save(flags);       保存中断请求标志
preempt_disable();          不允许抢占
_raw_spin_lock(lock);
__acquire(lock);
} while (0)

二、自旋锁综合使用

下面是一个使用的例子,你可以使用source insight查到它
/* never called when PTRS_PER_PMD > 1 */
void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused)
{
unsigned long flags; /* can be called from interrupt context */
spin_lock_irqsave(&pgd_lock, flags);  枷锁
pgd_list_del(pgd);
spin_unlock_irqrestore(&pgd_lock, flags); 释放
}
中断枷锁
#define spin_lock_irqsave(lock, flags) _spin_lock_irqsave(lock, flags)
分析
unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock)
{
unsigned long flags;
local_irq_save(flags); 将寄存器存入flags,并关中断
preempt_disable();   抢占锁
_raw_spin_lock_flags(lock, flags);  枷锁
return flags;
}
EXPORT_SYMBOL(_spin_lock_irqsave);
继续
/* For spinlocks etc */
#define local_irq_save(x) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
将标志寄存器的内容放在内存x中。请查看gcc汇编
继续
static inline void _raw_spin_lock_flags (spinlock_t *lock, unsigned long flags)
{
#ifdef CONFIG_DEBUG_SPINLOCK
if (unlikely(lock->magic != SPINLOCK_MAGIC)) {
printk("eip: %p ", __builtin_return_address(0));
BUG();
}
#endif
__asm__ __volatile__(
spin_lock_string_flags
:"=m" (lock->slock) : "r" (flags) : "memory");
}
继续
#define spin_lock_string_flags
" 1: "
"lock ; decb %0 "    ;lock总线锁住,原子操作
"jns 4f "
"2: "
"testl $0x200, %1 "
"jz 3f "
"sti "
"3: "
"rep;nop "
"cmpb $0, %0 "
"jle 3b "
"cli "
"jmp 1b "
"4: "
理解一下大概意思,就可以了。当lock-1后大于等于0就可以关中断继续执行了,否则nop空操作。Nop期间,cpu可以执行其他任务的代码。
解锁
#define spin_unlock_irqrestore(lock, flags) _spin_unlock_irqrestore(lock, flags)
void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
{
_raw_spin_unlock(lock);
local_irq_restore(flags);
preempt_enable();
}
static inline void _raw_spin_unlock(spinlock_t *lock)
{
#ifdef CONFIG_DEBUG_SPINLOCK
BUG_ON(lock->magic != SPINLOCK_MAGIC);
BUG_ON(!spin_is_locked(lock));
#endif
__asm__ __volatile__(
spin_unlock_string
);
}
Raw赤裸的解锁,表示最低沉的解锁原理。
#define spin_unlock_string
"xchgb %b0, %1"
:"=q" (oldval), "=m" (lock->slock)
:"0" (oldval) : "memory"
加1.解锁
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|文字版|手机版|DIY编程器网 ( 桂ICP备14005565号-1 )

GMT+8, 2025-1-10 13:01 , 耗时 0.187050 秒, 19 个查询请求 , Gzip 开启.

各位嘉宾言论仅代表个人观点,非属DIY编程器网立场。

桂公网安备 45031202000115号

DIY编程器群(超员):41210778 DIY编程器

DIY编程器群1(满员):3044634 DIY编程器1

diy编程器群2:551025008 diy编程器群2

QQ:28000622;Email:libyoufer@sina.com

本站由桂林市临桂区技兴电子商务经营部独家赞助。旨在技术交流,请自觉遵守国家法律法规,一旦发现将做封号删号处理。

快速回复 返回顶部 返回列表