LDREX/STREX and pre-emption on SMP hardware
Russell King - ARM Linux
linux at arm.linux.org.uk
Mon Sep 14 10:23:33 EDT 2009
On Mon, Sep 14, 2009 at 11:06:13AM +0100, Catalin Marinas wrote:
> On Mon, 2009-09-14 at 11:00 +0100, Russell King - ARM Linux wrote:
> > On Mon, Sep 14, 2009 at 02:43:53AM +0100, Jamie Lokier wrote:
> > > Catalin Marinas wrote:
> > > > With interrupts (I1, I2 interrupt handlers)
> > > >
> > > > I1 I2
> > > > LDREX
> > > > LDREX
> > > > STREX (succeeds)
> > > > STREX (fails)
> > > >
> > > > In the interrupt case, they are nested so the STREX in I2 is always
> > > > executed before STREX in I1 (you can extrapolate with several nested
> > > > interrupts).
> > >
> > > This assumes LDREX/STREX are always called in pairs. But this is in
> > > fact _not_ the case. Take a look at atomic_cmpxchg:
> > >
> > > do {
> > > __asm__ __volatile__("@ atomic_cmpxchg\n"
> > > "ldrex %1, [%2]\n"
> > > "mov %0, #0\n"
> > > "teq %1, %3\n"
> > > "strexeq %0, %4, [%2]\n"
> > > : "=&r" (res), "=&r" (oldval)
> > > : "r" (&ptr->counter), "Ir" (old), "r" (new)
> > > : "cc");
> > > } while (res);
> > >
> > > In the case where ptr->counter != old, STREX is not executed, and the
> > > do{...}while loop does not loop. Thus LDREX/STREX aren't paired.
> >
> > It doesn't matter though - consider two threads using LDREX on the same
> > location:
> >
> > T1 T2
> > LDREX
> > LDREX
> > STREXEQ (not satsified)
> > STREX
>
> As I replied to Jamie on a similar issue, you can have:
>
> T1 T2
> LDREX
> LDREX
> STREXEQ (satisfied, succeeds)
> LDREX
> STREXEQ (not satisfied)
> STREX (succeeds)
>
> Though this may be an unlikely sequence.
Actually, both of these can't happen because they imply a context switch
and a context switch clears the exclusive monitor. So the real sequence
is:
> > T1 T2
> > LDREX
CLREX
> > LDREX
> > STREXEQ (not satsified)
CLREX
> > STREX
which results in the STREX not succeeding. Ditto for your case.
More information about the linux-arm-kernel
mailing list