As for why your code hangs, this could be because of the WFE instruction.If no event happens, it will do nothing. Forever.Check prior if events are enabled and produced.
(Also, check the useage restrictions on STREX and LDREX in the ARM Architecture reference manual, that should be in section A2.9.4 "Usage restrictions")
There is an example on how to implement a spin lock on:https://www.doulos.com/knowhow/arm/Hints_and_Tips/Implementing_Semaphores/
Applying their example to your code would lead to something like this:
__asm__ __volatile__("@ocm_lock_mutex\n"" LDREX %[r2], [%[r0]]\n"" CMP %[r2], %[locked]\n"" STREXNE %[r2], %[locked], [%[r0]]\n"" CMPNE %[r2], #1\n"" BEQ ocm_lock_mutex\n" : [r2] "=r" (result), [r0] "=r" (mutex) : [locked] "r" (locked));
This will implement the mutex with busy waiting.
If you want your code to tell you if a mutex was acquired without the busy waiting, just modify the end:
__asm__ __volatile__("@ocm_lock_mutex\n"[...]" CMPNE %[r2], #1\n"" BEQ ocm_lock_mutex_end\n"" MOV %[r2], #2\n""@ocm_lock_mutex_end\n"" NOP\n" : [r2] "=r" (result), [r0] "=r" (mutex) : [locked] "r" (locked));
and just check in C:
if (result==0) {/*You didn't get the mutex, it was locked*/}else if (result==1) {/*You didn't get the mutex, access not exclusive*/}else if (result==2) {/*You got the mutex!*/}
(As indicated by the ARM Architecture Reference Manual, version 2005, A2.9.4 "Load and store operation")
It is entirely reasonable to construct the outside "busy waiting" loop in C.Or, if you want to have an interrupt-based scheme, suspend operation from there.
Rule(s) of thumb:
Keep your inline assembly code as small as possible and loop-free.
Make your inline assembly only do one thing at a time.