Skip to content

Instantly share code, notes, and snippets.

@sjlongland
Forked from hdznrrd/arm_cortex_m3_mutex.c
Last active January 17, 2018 13:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sjlongland/2efcbf110ad89e9eebc33b0f7fc1735f to your computer and use it in GitHub Desktop.
Save sjlongland/2efcbf110ad89e9eebc33b0f7fc1735f to your computer and use it in GitHub Desktop.
basic implementation of a no-block / no-wait mutex for ARM Cortex M3 and compatible models
/*!
* Cortex M3 mutex implementation.
* Ported to gcc by Stuart Longland <stuartl@vrt.com.au>
*
* Credit: https://gist.github.com/hdznrrd/4032002
*/
#ifndef _CM3MUTEX_H
#define _CM3MUTEX_H
#include <stdbool.h>
#include <stdint.h>
/*
* This is a very basic mutex implementation.
* Its aim is to try to acquire access to a critical section or fail.
* There is no spinlock or event-waiting going on.
* In case it fails to acquire the lock, it simply returns false.
*
* relevant read:
*
* Synchronization primitives
* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/BABHCIHB.html
*
* LDREX and STREX
* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/BABFFBJB.html
*
* In what situations might I need to insert memory barrier instructions?
* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka14041.html
*/
/*!
* Attempt to acquire a mutex. This operation is non-blocking.
*
* @param[inout] lock Mutex lock object
* @retval true Mutex acquired
* @retval false Mutex already acquired
*/
static inline _Bool mutex_acquire_asm(volatile uint8_t* lock) {
volatile uint8_t success;
__asm volatile(
/* Assembly routine template */
" MOV %[success], #1 ;\n" /* initialize success false */
" MOV R4, #1 ;\n" /* initialise our target lock state */
" LDREXB %[success], "
"[%[lock]] ;\n" /* Load the lock value */
" CMP %[success], #0 ;\n" /* Is the lock free? */
" ITTT EQ ;\n" /* IF ( EQUAL ) THEN { STREX, CMP, DMB } */
" STREXBEQ %[success], R4, "
"[%[lock]] ;\n" /* Try and claim the lock */
" CMPEQ %[success], #0 ;\n" /* Did this succeed? */
" DMBEQ ;\n" /* data memory barrier before
accessing restricted resource */
/* Outputs */
: [success] "=r" (success), /* =r: "we write to this register" */
[lock] "+r" (lock) /* +r: "we write to *and read from* this register */
/* Inputs */
:
/* Clobber list: this stuff is changed by our code */
: "memory", "r4" );
return success == 0;
}
/*!
* Release a mutex.
*
* @param[inout] lock Mutex lock object
* @retval true Mutex released
* @retval false Mutex already released
*/
static inline _Bool mutex_release_asm(volatile uint8_t* lock) {
volatile uint8_t success;
__asm volatile(
/* Assembly routine template */
" MOV %[success], #1 ;\n" /* initialize success false */
" MOV R4, #0 ;\n" /* initialise our target lock state */
" LDREXB %[success], "
"[%[lock]] ;\n" /* Load the lock value */
" CMP %[success], #1 ;\n" /* Is the lock in use? */
" ITTT EQ ;\n" /* IF ( EQUAL ) THEN { STREX, CMP, DMB } */
" STREXBEQ %[success], R4, "
"[%[lock]] ;\n" /* Try and release the lock */
" CMPEQ %[success], #0 ;\n" /* Did this succeed? */
" DMBEQ ;\n" /* data memory barrier before
accessing restricted resource */
/* Outputs */
: [success] "=r" (success), /* =r: "we write to this register" */
[lock] "+r" (lock) /* +r: "we write to *and read from* this register */
/* Inputs */
:
/* Clobber list: this stuff is changed by our code */
: "memory", "r4" );
return success == 0;
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment