mbed-os5 only for TYBLE16
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
Diff: platform/source/mbed_atomic_impl.c
- Revision:
- 1:9db0e321a9f4
- Parent:
- 0:5b88d5760320
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/platform/source/mbed_atomic_impl.c Tue Dec 31 06:02:27 2019 +0000 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2019, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "platform/mbed_assert.h" +#include "platform/mbed_atomic.h" +#include "platform/mbed_critical.h" + +/* Inline bool implementations in the header use uint8_t versions to manipulate the bool */ +MBED_STATIC_ASSERT(sizeof(bool) == sizeof(uint8_t), "Surely bool is a byte"); + +/* Inline implementations in the header use uint32_t versions to manipulate pointers */ +MBED_STATIC_ASSERT(sizeof(void *) == sizeof(uint32_t), "Alas, pointers must be 32-bit"); + + +#define DO_MBED_LOCKED_OP(name, OP, retValue, T, fn_suffix) \ +T core_util_atomic_##name##_##fn_suffix(volatile T *valuePtr, T arg) \ +{ \ + T oldValue, newValue; \ + core_util_critical_section_enter(); \ + oldValue = *valuePtr; \ + newValue = OP; \ + *valuePtr = newValue; \ + core_util_critical_section_exit(); \ + return retValue; \ +} + +#define DO_MBED_LOCKED_CAS_OP(T, fn_suffix) \ +bool core_util_atomic_cas_##fn_suffix(volatile T *ptr, T *expectedCurrentValue, T desiredValue) \ +{ \ + bool success; \ + T currentValue; \ + core_util_critical_section_enter(); \ + currentValue = *ptr; \ + if (currentValue == *expectedCurrentValue) { \ + *ptr = desiredValue; \ + success = true; \ + } else { \ + *expectedCurrentValue = currentValue; \ + success = false; \ + } \ + core_util_critical_section_exit(); \ + return success; \ +} \ + \ +bool core_util_atomic_compare_exchange_weak_##fn_suffix(volatile T *ptr, \ + T *expectedCurrentValue, T desiredValue) \ +{ \ + return core_util_atomic_cas_##fn_suffix(ptr, expectedCurrentValue, desiredValue); \ +} + +#if MBED_EXCLUSIVE_ACCESS +/* These are the C99 external definitions for the inline functions */ +/* We maintain external definitions rather than using "static inline" for backwards binary compatibility + * and to give the compiler plenty of leeway to choose to not inline in both C and C++ modes + */ + +extern inline bool core_util_atomic_flag_test_and_set(volatile core_util_atomic_flag *flagPtr); + +extern inline uint8_t core_util_atomic_exchange_u8(volatile uint8_t *valuePtr, uint8_t newValue); +extern inline uint16_t core_util_atomic_exchange_u16(volatile uint16_t *valuePtr, uint16_t newValue); +extern inline uint32_t core_util_atomic_exchange_u32(volatile uint32_t *valuePtr, uint32_t newValue); +extern inline uint8_t core_util_atomic_incr_u8(volatile uint8_t *valuePtr, uint8_t arg); +extern inline uint16_t core_util_atomic_incr_u16(volatile uint16_t *valuePtr, uint16_t arg); +extern inline uint32_t core_util_atomic_incr_u32(volatile uint32_t *valuePtr, uint32_t arg); +extern inline uint8_t core_util_atomic_decr_u8(volatile uint8_t *valuePtr, uint8_t arg); +extern inline uint16_t core_util_atomic_decr_u16(volatile uint16_t *valuePtr, uint16_t arg); +extern inline uint32_t core_util_atomic_decr_u32(volatile uint32_t *valuePtr, uint32_t arg); +extern inline uint8_t core_util_atomic_fetch_add_u8(volatile uint8_t *valuePtr, uint8_t arg); +extern inline uint16_t core_util_atomic_fetch_add_u16(volatile uint16_t *valuePtr, uint16_t arg); +extern inline uint32_t core_util_atomic_fetch_add_u32(volatile uint32_t *valuePtr, uint32_t arg); +extern inline uint8_t core_util_atomic_fetch_sub_u8(volatile uint8_t *valuePtr, uint8_t arg); +extern inline uint16_t core_util_atomic_fetch_sub_u16(volatile uint16_t *valuePtr, uint16_t arg); +extern inline uint32_t core_util_atomic_fetch_sub_u32(volatile uint32_t *valuePtr, uint32_t arg); +extern inline uint8_t core_util_atomic_fetch_and_u8(volatile uint8_t *valuePtr, uint8_t arg); +extern inline uint16_t core_util_atomic_fetch_and_u16(volatile uint16_t *valuePtr, uint16_t arg); +extern inline uint32_t core_util_atomic_fetch_and_u32(volatile uint32_t *valuePtr, uint32_t arg); +extern inline uint8_t core_util_atomic_fetch_or_u8(volatile uint8_t *valuePtr, uint8_t arg); +extern inline uint16_t core_util_atomic_fetch_or_u16(volatile uint16_t *valuePtr, uint16_t arg); +extern inline uint32_t core_util_atomic_fetch_or_u32(volatile uint32_t *valuePtr, uint32_t arg); +extern inline uint8_t core_util_atomic_fetch_xor_u8(volatile uint8_t *valuePtr, uint8_t arg); +extern inline uint16_t core_util_atomic_fetch_xor_u16(volatile uint16_t *valuePtr, uint16_t arg); +extern inline uint32_t core_util_atomic_fetch_xor_u32(volatile uint32_t *valuePtr, uint32_t arg); +extern inline bool core_util_atomic_cas_u8(volatile uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_t desiredValue); +extern inline bool core_util_atomic_cas_u16(volatile uint16_t *ptr, uint16_t *expectedCurrentValue, uint16_t desiredValue); +extern inline bool core_util_atomic_cas_u32(volatile uint32_t *ptr, uint32_t *expectedCurrentValue, uint32_t desiredValue); +extern inline bool core_util_atomic_compare_exchange_weak_u8(volatile uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_t desiredValue); +extern inline bool core_util_atomic_compare_exchange_weak_u16(volatile uint16_t *ptr, uint16_t *expectedCurrentValue, uint16_t desiredValue); +extern inline bool core_util_atomic_compare_exchange_weak_u32(volatile uint32_t *ptr, uint32_t *expectedCurrentValue, uint32_t desiredValue); + +#else + +bool core_util_atomic_flag_test_and_set(volatile core_util_atomic_flag *flagPtr) +{ + core_util_critical_section_enter(); + uint8_t currentValue = flagPtr->_flag; + flagPtr->_flag = true; + core_util_critical_section_exit(); + return currentValue; +} +#endif + +/* No architecture we support has LDREXD/STREXD, so must always disable IRQs for 64-bit operations */ +uint64_t core_util_atomic_load_u64(const volatile uint64_t *valuePtr) +{ + core_util_critical_section_enter(); + uint64_t currentValue = *valuePtr; + core_util_critical_section_exit(); + return currentValue; +} + +void core_util_atomic_store_u64(volatile uint64_t *valuePtr, uint64_t desiredValue) +{ + core_util_critical_section_enter(); + *valuePtr = desiredValue; + core_util_critical_section_exit(); +} + +/* Now locked operations for whichever we don't have lock-free ones for */ +#if MBED_EXCLUSIVE_ACCESS +/* Just need 64-bit locked operations */ +#define DO_MBED_LOCKED_OPS(name, OP, retValue) \ + DO_MBED_LOCKED_OP(name, OP, retValue, uint64_t, u64) +#define DO_MBED_LOCKED_CAS_OPS() \ + DO_MBED_LOCKED_CAS_OP(uint64_t, u64) +#else +/* All the operations are locked */ +#define DO_MBED_LOCKED_OPS(name, OP, retValue) \ + DO_MBED_LOCKED_OP(name, OP, retValue, uint8_t, u8) \ + DO_MBED_LOCKED_OP(name, OP, retValue, uint16_t, u16) \ + DO_MBED_LOCKED_OP(name, OP, retValue, uint32_t, u32) \ + DO_MBED_LOCKED_OP(name, OP, retValue, uint64_t, u64) +#define DO_MBED_LOCKED_CAS_OPS() \ + DO_MBED_LOCKED_CAS_OP(uint8_t, u8) \ + DO_MBED_LOCKED_CAS_OP(uint16_t, u16) \ + DO_MBED_LOCKED_CAS_OP(uint32_t, u32) \ + DO_MBED_LOCKED_CAS_OP(uint64_t, u64) +#endif + +// *INDENT-OFF* +DO_MBED_LOCKED_OPS(exchange, arg, oldValue) +DO_MBED_LOCKED_OPS(incr, oldValue + arg, newValue) +DO_MBED_LOCKED_OPS(decr, oldValue - arg, newValue) +DO_MBED_LOCKED_OPS(fetch_add, oldValue + arg, oldValue) +DO_MBED_LOCKED_OPS(fetch_sub, oldValue - arg, oldValue) +DO_MBED_LOCKED_OPS(fetch_and, oldValue & arg, oldValue) +DO_MBED_LOCKED_OPS(fetch_or, oldValue | arg, oldValue) +DO_MBED_LOCKED_OPS(fetch_xor, oldValue ^ arg, oldValue) +DO_MBED_LOCKED_CAS_OPS() +// *INDENT-ON* + +/* Similar functions for s32 etc are static inline, but these are extern inline for legacy binary compatibility */ +extern inline void *core_util_atomic_exchange_ptr(void *volatile *valuePtr, void *desiredValue); +extern inline void *core_util_atomic_incr_ptr(void *volatile *valuePtr, ptrdiff_t delta); +extern inline void *core_util_atomic_decr_ptr(void *volatile *valuePtr, ptrdiff_t delta); +extern inline bool core_util_atomic_cas_ptr(void *volatile *ptr, void **expectedCurrentValue, void *desiredValue);