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

Parents
  • You don't need to use CLREX.

    The whole point of DMB is to separate memory accesses before it from those after it. It is used so that if there are two different processors  accessing memory then they can access shared data in a coherent manner.  I do not know what you are using your counter for so I don't know where if anywhere you want a dmb. You need to use dmb in between setting or reading a flag controlling access to some shared data and accessing the data as in

    write a packet of data. dmb. Set flag saying data is ready

    read a flag and it says data is ready. dmb. read the data

Reply
  • You don't need to use CLREX.

    The whole point of DMB is to separate memory accesses before it from those after it. It is used so that if there are two different processors  accessing memory then they can access shared data in a coherent manner.  I do not know what you are using your counter for so I don't know where if anywhere you want a dmb. You need to use dmb in between setting or reading a flag controlling access to some shared data and accessing the data as in

    write a packet of data. dmb. Set flag saying data is ready

    read a flag and it says data is ready. dmb. read the data

Children
No data