This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Synchronization primitives, do I need CLREX?

Hi all,

I'm trying to understand the LDREX/STREX commands in an ARM Cortex M3 MCU to implement atomic access to various variables (the goal is to implement semaphores/mutexes or increment/decrement shared variables).

There are several ressources available:

[1] ARM Information Center LDREX/STREX

[2] ARM Information Center CLREX

[3] ARMv7-M Architecture Reference Manual

[4] Exclusive monitors http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/CIHHCAFD.html

[5] Synchronization primitives

[6] Memory barriers

While reviewing the ressources above I realized that:

1) LDREX/STREX must occur in pairs ([1])

2) STREX must use the same address the most recently executed LDREX used too, otherwise the behaviour is unpredictable (see [1])

3) The exclusive tag is cleared if 1) clrex instruction executed, 2) strex instr executed, 3) exception occurs (see [5])

4) When a context switch occurs, the monitors have to be reset either by CLREX (see [2]) (>ARMv6K) or by a dummy strex (see [4] §Resetting monitors or [3] §A2.9.3 and §A2.9.4 "usage restrictions 1."

5) LDREX + STREX must be close to each other in code (see [4]  §A2.9.4 "usage restrictions")

5) Memory barriers must be used [6]

I'm confused a bit here. On the one hand 3) states that if an exception (mainly interrupts in my case what is a type of exception) occurs, the state of the exclusive monitors will be reset. On the other hand 4) states a CLREX or a dummy STREX is required when a "context switch" is happening. Can a context switch take place without an exception?

So the big question is: Do I need to reset the exclusive monitors in each interrupt service routine or not? If I had to but don't do it the following could happen:

1) the main thread loads an address &a exclusively

2) an interrupt occurs

3) the ISR uses another address &b to increment a variable (LDREX + STREX pair). LDREX' last used address is &b then

4) the ISR returns to the main thread

5) the main thread tries to write the variable at address &a exclusively.

-> this should end in unpredictable behaviour because the last used LDREX is an other than used by STREX.

My current implementation follows:

[code]

int incVar(uint32_t * varAddr)

{

  uint32_t count;

  int32_t status;

  do

  {

    count = (uint32_t) __ldrex(  (uint32_t *)(varAddr) ); // load variable address exclusively

    status = __strex( ++count, (uint32_t *)(varAddr) ); // status != 0, if no exclusive access was guaranteed

  }

  while ( status != 0 );

  __dmb( 10 );        // recommended by arm -> make sure every memory access is done

  return SUCCESS;

}

[/code]

Is that usable and save?

Thank you very much,

Jan