分类: LINUX
2011-03-17 09:07:56
spin lock在单核模式下没有被实现,所以有个疑惑,既然没有被实现,为什么arm平台下的驱动大量使用spin lock做同步?于是发了下面的帖子:
有个网友的回复很好,snail_314的回复:
“spin lock未实现并不意味着spin_lock_irqsave是个空操作,它至少还有关中断\保护现场的操作,而spin_lock_irqrestore也有恢复现场\开中断的操作.所以,执行序和中断历程之间还是有保护的,赫赫”
另一个网友推荐了这篇文章:http://blog.chinaunix.net/u2/73067/showart_2046163.html
是好文章,但是太长,没耐心看下去。
总结了下,在单核arm平台,spin lock的下面几组操作函数的区别是:
spin_lock/unlock:为空,没有任何作用。
spin_lock_irq/unlock:关闭中断,避免冲突。
spin_lock_irqsave/unlock:同上,只是flags会保存调用spin_lock_irqsave时的中断状态。
ps:
1. 怎么使用查看代码,有时同一个符号会既有函数定义也有宏定义,这时千万别搞错,比如查看spin_lock实现时就犯了只查看函数实现没有查看宏定义的错误。
2. 延伸的问题:
与UP和SMP无关的定义:
typedef struct {
volatile unsigned int lock;
} spinlock_t;
#define SPIN_LOCK_UNLOCKED (spinlock_t){ 0 }
#define local_irq_save(x) __asm__ __volatile__(\"pushfl ; popl %0 ;
cli\":\"=g\" (x): /* no input */ :\"memory\")
spin_lock()在UP和SMP的不同:
UP下:
#define spin_lock(x) (void)lock
#define spin_unlock(x) do {} while(0)
可见,spin_lock(x)和spin_unlock(x)在UP环境下什么都不做。
SMP下:
void spin_lock(spinlock_t *plock)的执行过程如下:如果plock->lock=1,说明已被锁住,则 CPU 就不能去使用它所保护的资料结构;如果plock->lock=1,说明已被锁住,则可以从spin_lock()传回,接下去使用它所保护的资料。
spin_lock_irqsave()在UP和SMP的不同:
#define spin_lock_irqsave(lock,flags)
do { local_irq_save(flags); spin_lock(lock); } while (0)
可见在UP和SMP下,spin_lock_irqsave()的代码是一样的,但是由于“在UP和SMP下,spin_lock(lock)函数的实现不同”,导致了“在UP和SMP下,spin_lock_irqsave()函数的实现不同”。
local_irq_save(flags) 做的事就是将 CPU 的 flag 值先储存到 flags 变数里,然后将 CPU 的中断 diable 掉。这里将 CPU 的中断 disable 是指将执行这段 code 的 CPU,并不是指全部的 CPU。 也就是说它只会 disable local CPU 的中断。local_irq_save(flags)保证了本地cpu(执行这段code的cpu)不会打断临界区代码的执行;spin_lock()则保证了其他的cpu不会打断临界代码的执行。
举例:
spinlock t xxx lock = SPIN_LOCK_UNLOCKED;
unsigned long flags;
spin lock irqsave (&xxx lock, flags)
...critical section...
spin unlock irqrestore (&xxx lock, flags)
在UP下的实现:
spinlock_t xxx_lock = SPIN_LOCK_UNLOCKED;
unsigned long flags;
local_save_flags(flags);
... critical section ...
local_restore_flags(flags);
具体请查看:
spink_lock各个变种的区别:
1.有些情况下需要在访问共享资源时必须中断失效,而访问完后必须中断使能,这样的情形使用spin_lock_irq和spin_unlock_irq最好;
2.spin_lock_irqsave保存访问共享资源前的中断标志,然后失效中断;spin_unlock_irqrestore将恢复访问共享资源前的中断标志而不是直接使能中断;
3.如果被保护的共享资源只在进程上下文访问和软中断上下文访问,那么当在进程上下文访问共享资 源时,可能被软中断打断,从而可能进入软中断上下文来对被保护的共享资源访问,因此对于这种情况,对共享资源的访问必须使用spin_lock_bh和 spin_unlock_bh来保护。当然使用spin_lock_irq和spin_unlock_irq以及spin_lock_irqsave和 spin_unlock_irqrestore也可以,它们失效了本地硬中断,失效硬中断隐式地也失效了软中断。但是使用spin_lock_bh和 spin_unlock_bh是最恰当的,它比其他两个快。如果被保护的共享资源只在进程上下文和tasklet或timer上下文访问,那么应该使用与上面情况相同的获得和释放锁的宏,因为tasklet和timer是用软中断实现的。
4.对tasklet和timer和互斥操作
如果被保护的共享资源只在一个tasklet或timer上下文访问,那么不需要任何自旋锁保护,因为同一个tasklet或timer只能在一个CPU上运行,即使是在SMP环境下也是如此;如果被保护的共享资源只在两个或多个tasklet或timer上下文访问,那么对共享资源的访问仅需要用spin_lock和spin_unlock来 保护,不必使用_bh版本,因为当tasklet或timer运行时,不可能有其他tasklet或timer在当前CPU上运行。
5.spin_lock用于阻止在不同CPU上的执行单元对共享资源的同时访问以及不同进程上下文互相抢占导致的对共享资源的非同步访问,而中断失效和软中断失效却是为了阻止在同一CPU上软中断或中断对共享资源的非同步访问
详见: