分类: LINUX
2011-12-23 14:32:52
与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上软中断或中断对共享资源的非同步访问