volatile bool lock = false;
void func(void)
{
int i;
while(lock);
lock = true;
for(i = 0; i < 4; i++)
{
printk("pid = %d comm = %s
",
current->pid, current->comm);
mdelay(1000);
}
lock = false;
}
对于上面的例子,在SMP系统中,假设cpu0的进程A获得了锁,cpu1的进程B、 cpu2的进程C由于拿不到锁而一直在while处空转,等待锁的释放。但是当cpu0的进程A在释放锁时,如果不能保证原子性,那么cpu1的进程B、 cpu2的进程C是有可能同时拿到锁的,此时临界区中的资源访问就不会按照预定的方式执行。在C的软件层面上,是不能保证原子性的,那么只有在硬件层面上去保证,庆幸的是armv6及以上的版本支持strex和ldrex指令来保证多核之间的数据同步和控制并发问题。
static inline void arch_spin_lock(arch_spinlock_t *lock)
{
unsigned long tmp;
__asm__ __volatile__(
"1: ldrex %0, [%1] "
" teq %0, #0 " //TEQ 按位异或,这里判断tmp是否为0,即锁是否被占用。
WFE("ne") //tmp不等於0就执行WFE,使处理器进入a low-power state等待状态
" strexeq %0, %2, [%1] " //当前进程加锁操作,成功tmp=0,失败tmp=1
" teqeq %0, #0 "
" bne 1b"
: "=&r" (tmp)
: "r" (&lock->lock), "r" (1)
: "cc"); //如果你使用的指令会改变CPU的条件寄存器cc,需要在修改描述部分增加“cc”
smp_mb();
}
{
unsigned long tmp;
__asm__ __volatile__(
"1: ldrex %0, [%1] "
" teq %0, #0 " //TEQ 按位异或,这里判断tmp是否为0,即锁是否被占用。
WFE("ne") //tmp不等於0就执行WFE,使处理器进入a low-power state等待状态
" strexeq %0, %2, [%1] " //当前进程加锁操作,成功tmp=0,失败tmp=1
" teqeq %0, #0 "
" bne 1b"
: "=&r" (tmp)
: "r" (&lock->lock), "r" (1)
: "cc"); //如果你使用的指令会改变CPU的条件寄存器cc,需要在修改描述部分增加“cc”
smp_mb();
}
========================
WFE:
Wait For Event is a hint instruction that permits the processor to enter a low-power state until one of a number of
events occurs,
events occurs,
Encoding A1 ARMv6K, ARMv7 (executes as NOP in ARMv6T2)
WFE <c>
WFE <c>
========================
LDREX
Load Register Exclusive calculates an address from a base register value and an immediate offset, loads a word from
memory, writes it to a register and:
• if the address has the Shared Memory attribute, marks the physical address as exclusive access for the
executing processor in a global monitor
• causes the executing processor to indicate an active exclusive access in the local monitor.
Encoding A1 ARMv6*, ARMv7
LDREX<c> <Rt>, [<Rn>]
LDREX<c> <Rt>, [<Rn>]
Assembler syntax
LDREX{<c>}{<q>} <Rt>, [<Rn> {, #<imm>}]
where:
<c>, <q> See Standard assembler syntax fields on page A8-287.
<Rt> The destination register.
<Rn> The base register. The SP can be used.
<imm> The immediate offset added to the value of <Rn> to form the address. <imm> can be omitted, meaning
an offset of 0. Values are:
Encoding T1 multiples of 4 in the range 0-1020
Encoding A1 omitted or 0.
Operation
if ConditionPassed() then
EncodingSpecificOperations(); NullCheckIfThumbEE(n);
address = R[n] + imm32;
SetExclusiveMonitors(address,4);
R[t] = MemA[address,4];
==========================
STREX
Store Register Exclusive calculates an address from a base register value and an immediate offset, and stores a word
from a register to memory if the executing processor has exclusive access to the memory addressed.
Encoding A1 ARMv6*, ARMv7
STREX<c> <Rd>, <Rt>, [<Rn>]
Assembler syntax
STREX{<c>}{<q>} <Rd>, <Rt>, [<Rn> {, #<imm>}]
where:
<c>, <q> See Standard assembler syntax fields on page A8-287.
<Rd> The destination register for the returned status value. The value returned is:
0 if the operation updates memory
1 if the operation fails to update memory.
<Rt> The source register.
<Rn> The base register. The SP can be used.
<imm> The immediate offset added to the value of <Rn> to form the address. Values are multiples of 4 in the
range 0-1020 for encoding T1, and 0 for encoding A1. <imm> can be omitted, meaning an offset of 0.
Operation
if ConditionPassed() then
EncodingSpecificOperations(); NullCheckIfThumbEE(n);
address = R[n] + imm32;
if ExclusiveMonitorsPass(address,4) then
MemA[address,4] = R[t];
R[d] = 0;
else
R[d] = 1;