| /* | |
| * FreeRTOS Kernel <DEVELOPMENT BRANCH> | |
| * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. | |
| * | |
| * SPDX-License-Identifier: MIT | |
| * | |
| * Permission is hereby granted, free of charge, to any person obtaining a copy of | |
| * this software and associated documentation files (the "Software"), to deal in | |
| * the Software without restriction, including without limitation the rights to | |
| * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | |
| * the Software, and to permit persons to whom the Software is furnished to do so, | |
| * subject to the following conditions: | |
| * | |
| * The above copyright notice and this permission notice shall be included in all | |
| * copies or substantial portions of the Software. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | |
| * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | |
| * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
| * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| * | |
| * https://www.FreeRTOS.org | |
| * https://github.com/FreeRTOS | |
| * | |
| */ | |
| /** | |
| * @file atomic.h | |
| * @brief FreeRTOS atomic operation support. | |
| * | |
| * This file implements atomic functions by disabling interrupts globally. | |
| * Implementations with architecture specific atomic instructions can be | |
| * provided under each compiler directory. | |
| */ | |
| #ifndef ATOMIC_H | |
| #define ATOMIC_H | |
| #ifndef INC_FREERTOS_H | |
| #error "include FreeRTOS.h must appear in source files before include atomic.h" | |
| #endif | |
| /* Standard includes. */ | |
| #include <stdint.h> | |
| /* *INDENT-OFF* */ | |
| #ifdef __cplusplus | |
| extern "C" { | |
| #endif | |
| /* *INDENT-ON* */ | |
| /* | |
| * Port specific definitions -- entering/exiting critical section. | |
| * Refer template -- ./lib/FreeRTOS/portable/Compiler/Arch/portmacro.h | |
| * | |
| * Every call to ATOMIC_EXIT_CRITICAL() must be closely paired with | |
| * ATOMIC_ENTER_CRITICAL(). | |
| * | |
| */ | |
| #if defined( portSET_INTERRUPT_MASK_FROM_ISR ) | |
| /* Nested interrupt scheme is supported in this port. */ | |
| #define ATOMIC_ENTER_CRITICAL() \ | |
| UBaseType_t uxCriticalSectionType = portSET_INTERRUPT_MASK_FROM_ISR() | |
| #define ATOMIC_EXIT_CRITICAL() \ | |
| portCLEAR_INTERRUPT_MASK_FROM_ISR( uxCriticalSectionType ) | |
| #else | |
| /* Nested interrupt scheme is NOT supported in this port. */ | |
| #define ATOMIC_ENTER_CRITICAL() portENTER_CRITICAL() | |
| #define ATOMIC_EXIT_CRITICAL() portEXIT_CRITICAL() | |
| #endif /* portSET_INTERRUPT_MASK_FROM_ISR() */ | |
| /* | |
| * Port specific definition -- "always inline". | |
| * Inline is compiler specific, and may not always get inlined depending on your | |
| * optimization level. Also, inline is considered as performance optimization | |
| * for atomic. Thus, if portFORCE_INLINE is not provided by portmacro.h, | |
| * instead of resulting error, simply define it away. | |
| */ | |
| #ifndef portFORCE_INLINE | |
| #define portFORCE_INLINE | |
| #endif | |
| #define ATOMIC_COMPARE_AND_SWAP_SUCCESS 0x1U /**< Compare and swap succeeded, swapped. */ | |
| #define ATOMIC_COMPARE_AND_SWAP_FAILURE 0x0U /**< Compare and swap failed, did not swap. */ | |
| /*----------------------------- Swap && CAS ------------------------------*/ | |
| /** | |
| * Atomic compare-and-swap | |
| * | |
| * @brief Performs an atomic compare-and-swap operation on the specified values. | |
| * | |
| * @param[in, out] pulDestination Pointer to memory location from where value is | |
| * to be loaded and checked. | |
| * @param[in] ulExchange If condition meets, write this value to memory. | |
| * @param[in] ulComparand Swap condition. | |
| * | |
| * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. | |
| * | |
| * @note This function only swaps *pulDestination with ulExchange, if previous | |
| * *pulDestination value equals ulComparand. | |
| */ | |
| static portFORCE_INLINE uint32_t Atomic_CompareAndSwap_u32( uint32_t volatile * pulDestination, | |
| uint32_t ulExchange, | |
| uint32_t ulComparand ) | |
| { | |
| uint32_t ulReturnValue; | |
| ATOMIC_ENTER_CRITICAL(); | |
| { | |
| if( *pulDestination == ulComparand ) | |
| { | |
| *pulDestination = ulExchange; | |
| ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; | |
| } | |
| else | |
| { | |
| ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; | |
| } | |
| } | |
| ATOMIC_EXIT_CRITICAL(); | |
| return ulReturnValue; | |
| } | |
| /*-----------------------------------------------------------*/ | |
| /** | |
| * Atomic swap (pointers) | |
| * | |
| * @brief Atomically sets the address pointed to by *ppvDestination to the value | |
| * of *pvExchange. | |
| * | |
| * @param[in, out] ppvDestination Pointer to memory location from where a pointer | |
| * value is to be loaded and written back to. | |
| * @param[in] pvExchange Pointer value to be written to *ppvDestination. | |
| * | |
| * @return The initial value of *ppvDestination. | |
| */ | |
| static portFORCE_INLINE void * Atomic_SwapPointers_p32( void * volatile * ppvDestination, | |
| void * pvExchange ) | |
| { | |
| void * pReturnValue; | |
| ATOMIC_ENTER_CRITICAL(); | |
| { | |
| pReturnValue = *ppvDestination; | |
| *ppvDestination = pvExchange; | |
| } | |
| ATOMIC_EXIT_CRITICAL(); | |
| return pReturnValue; | |
| } | |
| /*-----------------------------------------------------------*/ | |
| /** | |
| * Atomic compare-and-swap (pointers) | |
| * | |
| * @brief Performs an atomic compare-and-swap operation on the specified pointer | |
| * values. | |
| * | |
| * @param[in, out] ppvDestination Pointer to memory location from where a pointer | |
| * value is to be loaded and checked. | |
| * @param[in] pvExchange If condition meets, write this value to memory. | |
| * @param[in] pvComparand Swap condition. | |
| * | |
| * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. | |
| * | |
| * @note This function only swaps *ppvDestination with pvExchange, if previous | |
| * *ppvDestination value equals pvComparand. | |
| */ | |
| static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32( void * volatile * ppvDestination, | |
| void * pvExchange, | |
| void * pvComparand ) | |
| { | |
| uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; | |
| ATOMIC_ENTER_CRITICAL(); | |
| { | |
| if( *ppvDestination == pvComparand ) | |
| { | |
| *ppvDestination = pvExchange; | |
| ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; | |
| } | |
| } | |
| ATOMIC_EXIT_CRITICAL(); | |
| return ulReturnValue; | |
| } | |
| /*----------------------------- Arithmetic ------------------------------*/ | |
| /** | |
| * Atomic add | |
| * | |
| * @brief Atomically adds count to the value of the specified pointer points to. | |
| * | |
| * @param[in,out] pulAddend Pointer to memory location from where value is to be | |
| * loaded and written back to. | |
| * @param[in] ulCount Value to be added to *pulAddend. | |
| * | |
| * @return previous *pulAddend value. | |
| */ | |
| static portFORCE_INLINE uint32_t Atomic_Add_u32( uint32_t volatile * pulAddend, | |
| uint32_t ulCount ) | |
| { | |
| uint32_t ulCurrent; | |
| ATOMIC_ENTER_CRITICAL(); | |
| { | |
| ulCurrent = *pulAddend; | |
| *pulAddend += ulCount; | |
| } | |
| ATOMIC_EXIT_CRITICAL(); | |
| return ulCurrent; | |
| } | |
| /*-----------------------------------------------------------*/ | |
| /** | |
| * Atomic subtract | |
| * | |
| * @brief Atomically subtracts count from the value of the specified pointer | |
| * pointers to. | |
| * | |
| * @param[in,out] pulAddend Pointer to memory location from where value is to be | |
| * loaded and written back to. | |
| * @param[in] ulCount Value to be subtract from *pulAddend. | |
| * | |
| * @return previous *pulAddend value. | |
| */ | |
| static portFORCE_INLINE uint32_t Atomic_Subtract_u32( uint32_t volatile * pulAddend, | |
| uint32_t ulCount ) | |
| { | |
| uint32_t ulCurrent; | |
| ATOMIC_ENTER_CRITICAL(); | |
| { | |
| ulCurrent = *pulAddend; | |
| *pulAddend -= ulCount; | |
| } | |
| ATOMIC_EXIT_CRITICAL(); | |
| return ulCurrent; | |
| } | |
| /*-----------------------------------------------------------*/ | |
| /** | |
| * Atomic increment | |
| * | |
| * @brief Atomically increments the value of the specified pointer points to. | |
| * | |
| * @param[in,out] pulAddend Pointer to memory location from where value is to be | |
| * loaded and written back to. | |
| * | |
| * @return *pulAddend value before increment. | |
| */ | |
| static portFORCE_INLINE uint32_t Atomic_Increment_u32( uint32_t volatile * pulAddend ) | |
| { | |
| uint32_t ulCurrent; | |
| ATOMIC_ENTER_CRITICAL(); | |
| { | |
| ulCurrent = *pulAddend; | |
| *pulAddend += 1; | |
| } | |
| ATOMIC_EXIT_CRITICAL(); | |
| return ulCurrent; | |
| } | |
| /*-----------------------------------------------------------*/ | |
| /** | |
| * Atomic decrement | |
| * | |
| * @brief Atomically decrements the value of the specified pointer points to | |
| * | |
| * @param[in,out] pulAddend Pointer to memory location from where value is to be | |
| * loaded and written back to. | |
| * | |
| * @return *pulAddend value before decrement. | |
| */ | |
| static portFORCE_INLINE uint32_t Atomic_Decrement_u32( uint32_t volatile * pulAddend ) | |
| { | |
| uint32_t ulCurrent; | |
| ATOMIC_ENTER_CRITICAL(); | |
| { | |
| ulCurrent = *pulAddend; | |
| *pulAddend -= 1; | |
| } | |
| ATOMIC_EXIT_CRITICAL(); | |
| return ulCurrent; | |
| } | |
| /*----------------------------- Bitwise Logical ------------------------------*/ | |
| /** | |
| * Atomic OR | |
| * | |
| * @brief Performs an atomic OR operation on the specified values. | |
| * | |
| * @param [in, out] pulDestination Pointer to memory location from where value is | |
| * to be loaded and written back to. | |
| * @param [in] ulValue Value to be ORed with *pulDestination. | |
| * | |
| * @return The original value of *pulDestination. | |
| */ | |
| static portFORCE_INLINE uint32_t Atomic_OR_u32( uint32_t volatile * pulDestination, | |
| uint32_t ulValue ) | |
| { | |
| uint32_t ulCurrent; | |
| ATOMIC_ENTER_CRITICAL(); | |
| { | |
| ulCurrent = *pulDestination; | |
| *pulDestination |= ulValue; | |
| } | |
| ATOMIC_EXIT_CRITICAL(); | |
| return ulCurrent; | |
| } | |
| /*-----------------------------------------------------------*/ | |
| /** | |
| * Atomic AND | |
| * | |
| * @brief Performs an atomic AND operation on the specified values. | |
| * | |
| * @param [in, out] pulDestination Pointer to memory location from where value is | |
| * to be loaded and written back to. | |
| * @param [in] ulValue Value to be ANDed with *pulDestination. | |
| * | |
| * @return The original value of *pulDestination. | |
| */ | |
| static portFORCE_INLINE uint32_t Atomic_AND_u32( uint32_t volatile * pulDestination, | |
| uint32_t ulValue ) | |
| { | |
| uint32_t ulCurrent; | |
| ATOMIC_ENTER_CRITICAL(); | |
| { | |
| ulCurrent = *pulDestination; | |
| *pulDestination &= ulValue; | |
| } | |
| ATOMIC_EXIT_CRITICAL(); | |
| return ulCurrent; | |
| } | |
| /*-----------------------------------------------------------*/ | |
| /** | |
| * Atomic NAND | |
| * | |
| * @brief Performs an atomic NAND operation on the specified values. | |
| * | |
| * @param [in, out] pulDestination Pointer to memory location from where value is | |
| * to be loaded and written back to. | |
| * @param [in] ulValue Value to be NANDed with *pulDestination. | |
| * | |
| * @return The original value of *pulDestination. | |
| */ | |
| static portFORCE_INLINE uint32_t Atomic_NAND_u32( uint32_t volatile * pulDestination, | |
| uint32_t ulValue ) | |
| { | |
| uint32_t ulCurrent; | |
| ATOMIC_ENTER_CRITICAL(); | |
| { | |
| ulCurrent = *pulDestination; | |
| *pulDestination = ~( ulCurrent & ulValue ); | |
| } | |
| ATOMIC_EXIT_CRITICAL(); | |
| return ulCurrent; | |
| } | |
| /*-----------------------------------------------------------*/ | |
| /** | |
| * Atomic XOR | |
| * | |
| * @brief Performs an atomic XOR operation on the specified values. | |
| * | |
| * @param [in, out] pulDestination Pointer to memory location from where value is | |
| * to be loaded and written back to. | |
| * @param [in] ulValue Value to be XORed with *pulDestination. | |
| * | |
| * @return The original value of *pulDestination. | |
| */ | |
| static portFORCE_INLINE uint32_t Atomic_XOR_u32( uint32_t volatile * pulDestination, | |
| uint32_t ulValue ) | |
| { | |
| uint32_t ulCurrent; | |
| ATOMIC_ENTER_CRITICAL(); | |
| { | |
| ulCurrent = *pulDestination; | |
| *pulDestination ^= ulValue; | |
| } | |
| ATOMIC_EXIT_CRITICAL(); | |
| return ulCurrent; | |
| } | |
| /* *INDENT-OFF* */ | |
| #ifdef __cplusplus | |
| } | |
| #endif | |
| /* *INDENT-ON* */ | |
| #endif /* ATOMIC_H */ |