Skip to content

Added cas instrinsics for pointer values #2054

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 7, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 88 additions & 11 deletions hal/api/critical.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#define __MBED_UTIL_CRITICAL_H__

#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -47,7 +49,7 @@ bool core_util_are_interrupts_enabled(void);
* section) will be preserved on exit from the section.
* 4) This implementation will currently only work on code running in privileged mode.
*/
void core_util_critical_section_enter();
void core_util_critical_section_enter(void);

/** Mark the end of a critical section
*
Expand All @@ -60,7 +62,7 @@ void core_util_critical_section_enter();
* section) will be preserved on exit from the section.
* 4) This implementation will currently only work on code running in privileged mode.
*/
void core_util_critical_section_exit();
void core_util_critical_section_exit(void);

/**
* Atomic compare and set. It compares the contents of a memory location to a
Expand Down Expand Up @@ -106,7 +108,7 @@ void core_util_critical_section_exit();
*
* function incr(p : pointer to int, a : int) returns int {
* done = false
* *value = *p // This fetch operation need not be atomic.
* value = *p // This fetch operation need not be atomic.
* while not done {
* done = atomic_cas(p, &value, value + a) // *value gets updated automatically until success
* }
Expand Down Expand Up @@ -159,7 +161,7 @@ bool core_util_atomic_cas_u8(uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_
*
* function incr(p : pointer to int, a : int) returns int {
* done = false
* *value = *p // This fetch operation need not be atomic.
* value = *p // This fetch operation need not be atomic.
* while not done {
* done = atomic_cas(p, &value, value + a) // *value gets updated automatically until success
* }
Expand Down Expand Up @@ -212,7 +214,7 @@ bool core_util_atomic_cas_u16(uint16_t *ptr, uint16_t *expectedCurrentValue, uin
*
* function incr(p : pointer to int, a : int) returns int {
* done = false
* *value = *p // This fetch operation need not be atomic.
* value = *p // This fetch operation need not be atomic.
* while not done {
* done = atomic_cas(p, &value, value + a) // *value gets updated automatically until success
* }
Expand All @@ -221,53 +223,128 @@ bool core_util_atomic_cas_u16(uint16_t *ptr, uint16_t *expectedCurrentValue, uin
*/
bool core_util_atomic_cas_u32(uint32_t *ptr, uint32_t *expectedCurrentValue, uint32_t desiredValue);

/**
* Atomic compare and set. It compares the contents of a memory location to a
* given value and, only if they are the same, modifies the contents of that
* memory location to a given new value. This is done as a single atomic
* operation. The atomicity guarantees that the new value is calculated based on
* up-to-date information; if the value had been updated by another thread in
* the meantime, the write would fail due to a mismatched expectedCurrentValue.
*
* Refer to https://en.wikipedia.org/wiki/Compare-and-set [which may redirect
* you to the article on compare-and swap].
*
* @param ptr The target memory location.
* @param[in,out] expectedCurrentValue A pointer to some location holding the
* expected current value of the data being set atomically.
* The computed 'desiredValue' should be a function of this current value.
* @Note: This is an in-out parameter. In the
* failure case of atomic_cas (where the
* destination isn't set), the pointee of expectedCurrentValue is
* updated with the current value.
* @param[in] desiredValue The new value computed based on '*expectedCurrentValue'.
*
* @return true if the memory location was atomically
* updated with the desired value (after verifying
* that it contained the expectedCurrentValue),
* false otherwise. In the failure case,
* exepctedCurrentValue is updated with the new
* value of the target memory location.
*
* pseudocode:
* function cas(p : pointer to int, old : pointer to int, new : int) returns bool {
* if *p != *old {
* *old = *p
* return false
* }
* *p = new
* return true
* }
*
* @Note: In the failure case (where the destination isn't set), the value
* pointed to by expectedCurrentValue is still updated with the current value.
* This property helps writing concise code for the following incr:
*
* function incr(p : pointer to int, a : int) returns int {
* done = false
* value = *p // This fetch operation need not be atomic.
* while not done {
* done = atomic_cas(p, &value, value + a) // *value gets updated automatically until success
* }
* return value + a
* }
*/
bool core_util_atomic_cas_ptr(void **ptr, void **expectedCurrentValue, void *desiredValue);

/**
* Atomic increment.
* @param valuePtr Target memory location being incremented.
* @param delta The amount being incremented.
* @return The new incremented value.
*/
uint8_t core_util_atomic_incr_u8(uint8_t * valuePtr, uint8_t delta);
uint8_t core_util_atomic_incr_u8(uint8_t *valuePtr, uint8_t delta);

/**
* Atomic increment.
* @param valuePtr Target memory location being incremented.
* @param delta The amount being incremented.
* @return The new incremented value.
*/
uint16_t core_util_atomic_incr_u16(uint16_t * valuePtr, uint16_t delta);
uint16_t core_util_atomic_incr_u16(uint16_t *valuePtr, uint16_t delta);

/**
* Atomic increment.
* @param valuePtr Target memory location being incremented.
* @param delta The amount being incremented.
* @return The new incremented value.
*/
uint32_t core_util_atomic_incr_u32(uint32_t * valuePtr, uint32_t delta);
uint32_t core_util_atomic_incr_u32(uint32_t *valuePtr, uint32_t delta);

/**
* Atomic increment.
* @param valuePtr Target memory location being incremented.
* @param delta The amount being incremented in bytes.
* @return The new incremented value.
*
* @note The type of the pointer argument is not taken into account
* and the pointer is incremented by bytes.
*/
void *core_util_atomic_incr_ptr(void **valuePtr, ptrdiff_t delta);

/**
* Atomic decrement.
* @param valuePtr Target memory location being decremented.
* @param delta The amount being decremented.
* @return The new decremented value.
*/
uint8_t core_util_atomic_decr_u8(uint8_t * valuePtr, uint8_t delta);
uint8_t core_util_atomic_decr_u8(uint8_t *valuePtr, uint8_t delta);

/**
* Atomic decrement.
* @param valuePtr Target memory location being decremented.
* @param delta The amount being decremented.
* @return The new decremented value.
*/
uint16_t core_util_atomic_decr_u16(uint16_t * valuePtr, uint16_t delta);
uint16_t core_util_atomic_decr_u16(uint16_t *valuePtr, uint16_t delta);

/**
* Atomic decrement.
* @param valuePtr Target memory location being decremented.
* @param delta The amount being decremented.
* @return The new decremented value.
*/
uint32_t core_util_atomic_decr_u32(uint32_t * valuePtr, uint32_t delta);
uint32_t core_util_atomic_decr_u32(uint32_t *valuePtr, uint32_t delta);

/**
* Atomic decrement.
* @param valuePtr Target memory location being decremented.
* @param delta The amount being decremented in bytes.
* @return The new decremented value.
*
* @note The type of the pointer argument is not taken into account
* and the pointer is decremented by bytes
*/
void *core_util_atomic_decr_ptr(void **valuePtr, ptrdiff_t delta);

#ifdef __cplusplus
} // extern "C"
Expand Down
51 changes: 31 additions & 20 deletions hal/common/critical.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,11 @@
* limitations under the License.
*/

#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include <stddef.h>
#include "critical.h"

#include "cmsis.h"
#include "mbed_assert.h"

// Module include
#include "critical.h"

#define EXCLUSIVE_ACCESS (!defined (__CORTEX_M0) && !defined (__CORTEX_M0PLUS))

static volatile uint32_t interrupt_enable_counter = 0;
Expand All @@ -38,7 +34,7 @@ bool core_util_are_interrupts_enabled(void)
#endif
}

void core_util_critical_section_enter()
void core_util_critical_section_enter(void)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please don't mix unrelated changes. You should submit them in separate pull requests. This is not a matter of convenience.

{
bool interrupts_disabled = !core_util_are_interrupts_enabled();
__disable_irq();
Expand All @@ -63,7 +59,7 @@ void core_util_critical_section_enter()
interrupt_enable_counter++;
}

void core_util_critical_section_exit()
void core_util_critical_section_exit(void)
{
/* If critical_section_enter has not previously been called, do nothing */
if (interrupt_enable_counter) {
Expand Down Expand Up @@ -127,7 +123,7 @@ bool core_util_atomic_cas_u32(uint32_t *ptr, uint32_t *expectedCurrentValue, uin
return !__STREXW(desiredValue, (volatile uint32_t*)ptr);
}

uint8_t core_util_atomic_incr_u8(uint8_t * valuePtr, uint8_t delta)
uint8_t core_util_atomic_incr_u8(uint8_t *valuePtr, uint8_t delta)
{
uint8_t newValue;
do {
Expand All @@ -136,7 +132,7 @@ uint8_t core_util_atomic_incr_u8(uint8_t * valuePtr, uint8_t delta)
return newValue;
}

uint16_t core_util_atomic_incr_u16(uint16_t * valuePtr, uint16_t delta)
uint16_t core_util_atomic_incr_u16(uint16_t *valuePtr, uint16_t delta)
{
uint16_t newValue;
do {
Expand All @@ -145,7 +141,7 @@ uint16_t core_util_atomic_incr_u16(uint16_t * valuePtr, uint16_t delta)
return newValue;
}

uint32_t core_util_atomic_incr_u32(uint32_t * valuePtr, uint32_t delta)
uint32_t core_util_atomic_incr_u32(uint32_t *valuePtr, uint32_t delta)
{
uint32_t newValue;
do {
Expand All @@ -155,7 +151,7 @@ uint32_t core_util_atomic_incr_u32(uint32_t * valuePtr, uint32_t delta)
}


uint8_t core_util_atomic_decr_u8(uint8_t * valuePtr, uint8_t delta)
uint8_t core_util_atomic_decr_u8(uint8_t *valuePtr, uint8_t delta)
{
uint8_t newValue;
do {
Expand All @@ -164,7 +160,7 @@ uint8_t core_util_atomic_decr_u8(uint8_t * valuePtr, uint8_t delta)
return newValue;
}

uint16_t core_util_atomic_decr_u16(uint16_t * valuePtr, uint16_t delta)
uint16_t core_util_atomic_decr_u16(uint16_t *valuePtr, uint16_t delta)
{
uint16_t newValue;
do {
Expand All @@ -173,7 +169,7 @@ uint16_t core_util_atomic_decr_u16(uint16_t * valuePtr, uint16_t delta)
return newValue;
}

uint32_t core_util_atomic_decr_u32(uint32_t * valuePtr, uint32_t delta)
uint32_t core_util_atomic_decr_u32(uint32_t *valuePtr, uint32_t delta)
{
uint32_t newValue;
do {
Expand Down Expand Up @@ -236,7 +232,14 @@ bool core_util_atomic_cas_u32(uint32_t *ptr, uint32_t *expectedCurrentValue, uin
return success;
}

uint8_t core_util_atomic_incr_u8(uint8_t * valuePtr, uint8_t delta)
bool core_util_atomic_cas_ptr(void **ptr, void **expectedCurrentValue, void *desiredValue) {
return core_util_atomic_cas_u32(
(uintptr_t *)ptr,
(uintptr_t *)expectedCurrentValue,
(uintptr_t)desiredValue);
}

uint8_t core_util_atomic_incr_u8(uint8_t *valuePtr, uint8_t delta)
{
uint8_t newValue;
core_util_critical_section_enter();
Expand All @@ -246,7 +249,7 @@ uint8_t core_util_atomic_incr_u8(uint8_t * valuePtr, uint8_t delta)
return newValue;
}

uint16_t core_util_atomic_incr_u16(uint16_t * valuePtr, uint16_t delta)
uint16_t core_util_atomic_incr_u16(uint16_t *valuePtr, uint16_t delta)
{
uint16_t newValue;
core_util_critical_section_enter();
Expand All @@ -256,7 +259,7 @@ uint16_t core_util_atomic_incr_u16(uint16_t * valuePtr, uint16_t delta)
return newValue;
}

uint32_t core_util_atomic_incr_u32(uint32_t * valuePtr, uint32_t delta)
uint32_t core_util_atomic_incr_u32(uint32_t *valuePtr, uint32_t delta)
{
uint32_t newValue;
core_util_critical_section_enter();
Expand All @@ -266,8 +269,12 @@ uint32_t core_util_atomic_incr_u32(uint32_t * valuePtr, uint32_t delta)
return newValue;
}

void *core_util_atomic_incr_ptr(void **valuePtr, ptrdiff_t delta) {
return core_util_atomic_incr((uintptr_t)valuePtr, (uintptr_t)delta);
}


uint8_t core_util_atomic_decr_u8(uint8_t * valuePtr, uint8_t delta)
uint8_t core_util_atomic_decr_u8(uint8_t *valuePtr, uint8_t delta)
{
uint8_t newValue;
core_util_critical_section_enter();
Expand All @@ -277,7 +284,7 @@ uint8_t core_util_atomic_decr_u8(uint8_t * valuePtr, uint8_t delta)
return newValue;
}

uint16_t core_util_atomic_decr_u16(uint16_t * valuePtr, uint16_t delta)
uint16_t core_util_atomic_decr_u16(uint16_t *valuePtr, uint16_t delta)
{
uint16_t newValue;
core_util_critical_section_enter();
Expand All @@ -287,7 +294,7 @@ uint16_t core_util_atomic_decr_u16(uint16_t * valuePtr, uint16_t delta)
return newValue;
}

uint32_t core_util_atomic_decr_u32(uint32_t * valuePtr, uint32_t delta)
uint32_t core_util_atomic_decr_u32(uint32_t *valuePtr, uint32_t delta)
{
uint32_t newValue;
core_util_critical_section_enter();
Expand All @@ -297,5 +304,9 @@ uint32_t core_util_atomic_decr_u32(uint32_t * valuePtr, uint32_t delta)
return newValue;
}

void *core_util_atomic_decr_ptr(void **valuePtr, ptrdiff_t delta) {
return core_util_atomic_decr((uintptr_t)valuePtr, (uintptr_t)delta);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where's core_util_atomic_decr/incr function defined? It does not build.

}

#endif