2 * FreeRTOS Kernel <DEVELOPMENT BRANCH>
3 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 * SPDX-License-Identifier: MIT
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 * the Software, and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * https://www.FreeRTOS.org
25 * https://github.com/FreeRTOS
31 * @brief FreeRTOS atomic operation support.
33 * This file implements atomic functions by disabling interrupts globally.
34 * Implementations with architecture specific atomic instructions can be
35 * provided under each compiler directory.
37 * The atomic interface can be used in FreeRTOS tasks on all FreeRTOS ports. It
38 * can also be used in Interrupt Service Routines (ISRs) on FreeRTOS ports that
39 * support nested interrupts (i.e. portHAS_NESTED_INTERRUPTS is set to 1). The
40 * atomic interface must not be used in ISRs on FreeRTOS ports that do not
41 * support nested interrupts (i.e. portHAS_NESTED_INTERRUPTS is set to 0)
42 * because ISRs on these ports cannot be interrupted and therefore, do not need
49 #ifndef INC_FREERTOS_H
50 #error "include FreeRTOS.h must appear in source files before include atomic.h"
53 /* Standard includes. */
63 * Port specific definitions -- entering/exiting critical section.
64 * Refer template -- ./lib/FreeRTOS/portable/Compiler/Arch/portmacro.h
66 * Every call to ATOMIC_EXIT_CRITICAL() must be closely paired with
67 * ATOMIC_ENTER_CRITICAL().
70 #if ( portHAS_NESTED_INTERRUPTS == 1 )
72 /* Nested interrupt scheme is supported in this port. */
73 #define ATOMIC_ENTER_CRITICAL() \
74 UBaseType_t uxCriticalSectionType = portSET_INTERRUPT_MASK_FROM_ISR()
76 #define ATOMIC_EXIT_CRITICAL() \
77 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxCriticalSectionType )
81 /* Nested interrupt scheme is NOT supported in this port. */
82 #define ATOMIC_ENTER_CRITICAL() portENTER_CRITICAL()
83 #define ATOMIC_EXIT_CRITICAL() portEXIT_CRITICAL()
85 #endif /* portSET_INTERRUPT_MASK_FROM_ISR() */
88 * Port specific definition -- "always inline".
89 * Inline is compiler specific, and may not always get inlined depending on your
90 * optimization level. Also, inline is considered as performance optimization
91 * for atomic. Thus, if portFORCE_INLINE is not provided by portmacro.h,
92 * instead of resulting error, simply define it away.
94 #ifndef portFORCE_INLINE
95 #define portFORCE_INLINE
98 #define ATOMIC_COMPARE_AND_SWAP_SUCCESS 0x1U /**< Compare and swap succeeded, swapped. */
99 #define ATOMIC_COMPARE_AND_SWAP_FAILURE 0x0U /**< Compare and swap failed, did not swap. */
101 /*----------------------------- Swap && CAS ------------------------------*/
104 * Atomic compare-and-swap
106 * @brief Performs an atomic compare-and-swap operation on the specified values.
108 * @param[in, out] pulDestination Pointer to memory location from where value is
109 * to be loaded and checked.
110 * @param[in] ulExchange If condition meets, write this value to memory.
111 * @param[in] ulComparand Swap condition.
113 * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped.
115 * @note This function only swaps *pulDestination with ulExchange, if previous
116 * *pulDestination value equals ulComparand.
118 static portFORCE_INLINE uint32_t Atomic_CompareAndSwap_u32( uint32_t volatile * pulDestination,
120 uint32_t ulComparand )
122 uint32_t ulReturnValue;
124 ATOMIC_ENTER_CRITICAL();
126 if( *pulDestination == ulComparand )
128 *pulDestination = ulExchange;
129 ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;
133 ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE;
136 ATOMIC_EXIT_CRITICAL();
138 return ulReturnValue;
140 /*-----------------------------------------------------------*/
143 * Atomic swap (pointers)
145 * @brief Atomically sets the address pointed to by *ppvDestination to the value
148 * @param[in, out] ppvDestination Pointer to memory location from where a pointer
149 * value is to be loaded and written back to.
150 * @param[in] pvExchange Pointer value to be written to *ppvDestination.
152 * @return The initial value of *ppvDestination.
154 static portFORCE_INLINE void * Atomic_SwapPointers_p32( void * volatile * ppvDestination,
159 ATOMIC_ENTER_CRITICAL();
161 pReturnValue = *ppvDestination;
162 *ppvDestination = pvExchange;
164 ATOMIC_EXIT_CRITICAL();
168 /*-----------------------------------------------------------*/
171 * Atomic compare-and-swap (pointers)
173 * @brief Performs an atomic compare-and-swap operation on the specified pointer
176 * @param[in, out] ppvDestination Pointer to memory location from where a pointer
177 * value is to be loaded and checked.
178 * @param[in] pvExchange If condition meets, write this value to memory.
179 * @param[in] pvComparand Swap condition.
181 * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped.
183 * @note This function only swaps *ppvDestination with pvExchange, if previous
184 * *ppvDestination value equals pvComparand.
186 static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32( void * volatile * ppvDestination,
190 uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE;
192 ATOMIC_ENTER_CRITICAL();
194 if( *ppvDestination == pvComparand )
196 *ppvDestination = pvExchange;
197 ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;
200 ATOMIC_EXIT_CRITICAL();
202 return ulReturnValue;
206 /*----------------------------- Arithmetic ------------------------------*/
211 * @brief Atomically adds count to the value of the specified pointer points to.
213 * @param[in,out] pulAddend Pointer to memory location from where value is to be
214 * loaded and written back to.
215 * @param[in] ulCount Value to be added to *pulAddend.
217 * @return previous *pulAddend value.
219 static portFORCE_INLINE uint32_t Atomic_Add_u32( uint32_t volatile * pulAddend,
224 ATOMIC_ENTER_CRITICAL();
226 ulCurrent = *pulAddend;
227 *pulAddend += ulCount;
229 ATOMIC_EXIT_CRITICAL();
233 /*-----------------------------------------------------------*/
238 * @brief Atomically subtracts count from the value of the specified pointer
241 * @param[in,out] pulAddend Pointer to memory location from where value is to be
242 * loaded and written back to.
243 * @param[in] ulCount Value to be subtract from *pulAddend.
245 * @return previous *pulAddend value.
247 static portFORCE_INLINE uint32_t Atomic_Subtract_u32( uint32_t volatile * pulAddend,
252 ATOMIC_ENTER_CRITICAL();
254 ulCurrent = *pulAddend;
255 *pulAddend -= ulCount;
257 ATOMIC_EXIT_CRITICAL();
261 /*-----------------------------------------------------------*/
266 * @brief Atomically increments the value of the specified pointer points to.
268 * @param[in,out] pulAddend Pointer to memory location from where value is to be
269 * loaded and written back to.
271 * @return *pulAddend value before increment.
273 static portFORCE_INLINE uint32_t Atomic_Increment_u32( uint32_t volatile * pulAddend )
277 ATOMIC_ENTER_CRITICAL();
279 ulCurrent = *pulAddend;
282 ATOMIC_EXIT_CRITICAL();
286 /*-----------------------------------------------------------*/
291 * @brief Atomically decrements the value of the specified pointer points to
293 * @param[in,out] pulAddend Pointer to memory location from where value is to be
294 * loaded and written back to.
296 * @return *pulAddend value before decrement.
298 static portFORCE_INLINE uint32_t Atomic_Decrement_u32( uint32_t volatile * pulAddend )
302 ATOMIC_ENTER_CRITICAL();
304 ulCurrent = *pulAddend;
307 ATOMIC_EXIT_CRITICAL();
312 /*----------------------------- Bitwise Logical ------------------------------*/
317 * @brief Performs an atomic OR operation on the specified values.
319 * @param [in, out] pulDestination Pointer to memory location from where value is
320 * to be loaded and written back to.
321 * @param [in] ulValue Value to be ORed with *pulDestination.
323 * @return The original value of *pulDestination.
325 static portFORCE_INLINE uint32_t Atomic_OR_u32( uint32_t volatile * pulDestination,
330 ATOMIC_ENTER_CRITICAL();
332 ulCurrent = *pulDestination;
333 *pulDestination |= ulValue;
335 ATOMIC_EXIT_CRITICAL();
339 /*-----------------------------------------------------------*/
344 * @brief Performs an atomic AND operation on the specified values.
346 * @param [in, out] pulDestination Pointer to memory location from where value is
347 * to be loaded and written back to.
348 * @param [in] ulValue Value to be ANDed with *pulDestination.
350 * @return The original value of *pulDestination.
352 static portFORCE_INLINE uint32_t Atomic_AND_u32( uint32_t volatile * pulDestination,
357 ATOMIC_ENTER_CRITICAL();
359 ulCurrent = *pulDestination;
360 *pulDestination &= ulValue;
362 ATOMIC_EXIT_CRITICAL();
366 /*-----------------------------------------------------------*/
371 * @brief Performs an atomic NAND operation on the specified values.
373 * @param [in, out] pulDestination Pointer to memory location from where value is
374 * to be loaded and written back to.
375 * @param [in] ulValue Value to be NANDed with *pulDestination.
377 * @return The original value of *pulDestination.
379 static portFORCE_INLINE uint32_t Atomic_NAND_u32( uint32_t volatile * pulDestination,
384 ATOMIC_ENTER_CRITICAL();
386 ulCurrent = *pulDestination;
387 *pulDestination = ~( ulCurrent & ulValue );
389 ATOMIC_EXIT_CRITICAL();
393 /*-----------------------------------------------------------*/
398 * @brief Performs an atomic XOR operation on the specified values.
400 * @param [in, out] pulDestination Pointer to memory location from where value is
401 * to be loaded and written back to.
402 * @param [in] ulValue Value to be XORed with *pulDestination.
404 * @return The original value of *pulDestination.
406 static portFORCE_INLINE uint32_t Atomic_XOR_u32( uint32_t volatile * pulDestination,
411 ATOMIC_ENTER_CRITICAL();
413 ulCurrent = *pulDestination;
414 *pulDestination ^= ulValue;
416 ATOMIC_EXIT_CRITICAL();
427 #endif /* ATOMIC_H */