[parisc-linux] atomic_t
Matthew Wilcox
willy@debian.org
Sun, 13 Jan 2002 21:15:08 +0000
Just thinking about atomic_set taking the spinlock to assure
exclusivity... I thought we could eliminate it.
Here's the current code:
static __inline__ void __atomic_set(atomic_t *v, int i)
{
unsigned long flags;
SPIN_LOCK_IRQSAVE(ATOMIC_HASH(v), flags);
v->counter = i;
SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(v), flags);
}
static __inline__ int __atomic_add_return(int i, atomic_t *v)
{
int ret;
unsigned long flags;
SPIN_LOCK_IRQSAVE(ATOMIC_HASH(v), flags);
ret = (v->counter += i);
SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(v), flags);
return ret;
}
The legitimate effect of having two processors do this at the same time
are:
atomic_t v = 3
case 1:
atomic_add_return(1, &v)
atomic_set(&v, 1)
result: v = 1, a_a_r returns 4.
or case 2:
atomic_set(&v, 1)
atomic_add_return(1, &v)
result: v = 2, a_a_r returns 2.
The spinlocks guarantee this behaviour, but let's look at what happens
if we remove the spinlock from atomic_set. Now atomic_set is just an
assignment, and can occur at any point during atomic_add_ret. We'll have
to drop to psuedo-assembler for this.
atomic_add_ret becomes:
a) lock
b) load v into register r
c) add 1 to r
d) store r to v
e) unlock
f) return r
atomic_set (store 1 to v) can appear to occur at any point -- the CPU
ref manual guarantees it won't cause any problems.
Before step b leads to case 2. after step d leads to case 1. between
steps b and d, it's as if the atomic_set _never_happened_. It results
in v=4, a_a_r returns 4.
The question is whether any code relies on this behaviour. It probably
does in some of the messier bits of networking :-(
--
Revolutions do not require corporate support.