一、自旋锁
自旋锁是专为防止多处理器并发而引入的一种锁,它在内核中大量应用于中断处理等部分(对于单处理器来说,防止中断处理中的并发可简单采用关闭中断的方式,即在标志寄存器中关闭/打开中断标志位,不需要自旋锁)。
自旋就是自己连续的循环等待。如果你有抱着你的爱人旋转的经历,那么你应该知道一件事情,为了安全,你不能旋转太久,你的爱人如果头昏,也想你早日释放。是的,自旋的缺点,就是它频繁的循环直到等待锁的释放,将它用于可以快速完成的代码中才好。
自旋不能抢占,但能中断。
相关话题: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_magic0x1d244b3c
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.解锁
简易抛物面天线的制作,卫星天线制作
禾多科技与AUTOSAR国际组织签署合作协议
iPhone6对比iPhone XS速度测试
统一可视化融合物联综合管理平台简介
AP8663升压恒压驱动芯片 输入2.6-5.5V输出3.0-25V
Linux内核同步机制的自旋锁原理
iOS11正式版今日凌晨已推送:iOS11正式版如何升级?需要注意什么事项?iOS11正式版有哪些新功能?
衰减器作用
IGBT稳态分析—电流与电荷分布的初步分析(2)
季度畅销款AdvantestR3765C网络分析仪R3765C
谷歌正在探索苹果公司新的反跟踪功能的替代方案
YouTube与谷歌同时启动裁员
新加坡将部署人脸识别系统,不需要身份证
电压比较器的电路构成,电压比较器的原理框图及引脚功能
PCB背钻加工方法与注意事项
倒车雷达的探测头数量
7家电视企业被告知整顿开机广告问题,不应成为“标配”功能之一
绿厂不愧是绿厂,oppor9s花俩星期就把华为p10草木绿抄走了
史上最励志快递哥:曾是一名无闻的快递员,现马云都很待见他,开宝马月入超20万
PWM直流电机驱动电路及程序