-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* Cortex M3 mutex implementation. | |
* Ported to gcc by Stuart Longland <[email protected]> | |
* | |
* 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