Platform API Reference
Platform portability layer
atomic.h
Go to the documentation of this file.
1 /*
2  * FreeRTOS Kernel V10.2.0
3  * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * http://www.FreeRTOS.org
23  * http://aws.amazon.com/freertos
24  *
25  * 1 tab == 4 spaces!
26  */
27 
49 #ifndef ATOMIC_H
50 #define ATOMIC_H
51 
52 #ifndef INC_FREERTOS_H
53  #error "include FreeRTOS.h must appear in source files before include atomic.h"
54 #endif
55 
56 /* Standard includes. */
57 #include <stdint.h>
58 
59 #ifdef __cplusplus
60 extern "C" {
61 #endif
62 
63 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )
64 
65  /* Needed for __atomic_compare_exchange() weak=false. */
66  #include <stdbool.h>
67 
68  /* This branch is for GCC compiler and GCC compiler only. */
69  #ifndef portFORCE_INLINE
70  #define portFORCE_INLINE inline __attribute__((always_inline))
71  #endif
72 
73 #else
74 
75  /* Port specific definitions -- entering/exiting critical section.
76  * Refer template -- ./lib/FreeRTOS/portable/Compiler/Arch/portmacro.h
77  *
78  * Every call to ATOMIC_EXIT_CRITICAL() must be closely paired with
79  * ATOMIC_ENTER_CRITICAL().
80  */
81  #if defined( portSET_INTERRUPT_MASK_FROM_ISR )
82 
83  /* Nested interrupt scheme is supported in this port. */
84  #define ATOMIC_ENTER_CRITICAL() \
85  UBaseType_t uxCriticalSectionType = portSET_INTERRUPT_MASK_FROM_ISR()
86 
87  #define ATOMIC_EXIT_CRITICAL() \
88  portCLEAR_INTERRUPT_MASK_FROM_ISR( uxCriticalSectionType )
89 
90  #else
91 
92  /* Nested interrupt scheme is NOT supported in this port. */
93  #define ATOMIC_ENTER_CRITICAL() portENTER_CRITICAL()
94  #define ATOMIC_EXIT_CRITICAL() portEXIT_CRITICAL()
95 
96  #endif /* portSET_INTERRUPT_MASK_FROM_ISR() */
97 
98  /* Port specific definition -- "always inline".
99  * Inline is compiler specific, and may not always get inlined depending on your optimization level.
100  * Also, inline is considerred as performance optimization for atomic.
101  * Thus, if portFORCE_INLINE is not provided by portmacro.h, instead of resulting error,
102  * simply define it.
103  */
104  #ifndef portFORCE_INLINE
105  #define portFORCE_INLINE
106  #endif
107 
108 #endif /* configUSE_GCC_BUILTIN_ATOMICS */
109 
110 #define ATOMIC_COMPARE_AND_SWAP_SUCCESS 0x1U
111 #define ATOMIC_COMPARE_AND_SWAP_FAILURE 0x0U
113 /*----------------------------- Swap && CAS ------------------------------*/
114 
130 static portFORCE_INLINE uint32_t Atomic_CompareAndSwap_u32(
131  uint32_t volatile * pDestination,
132  uint32_t ulExchange,
133  uint32_t ulComparand )
134 {
135 
136  uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE;
137 
138 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )
139 
140  if ( __atomic_compare_exchange( pDestination,
141  &ulComparand,
142  &ulExchange,
143  false,
144  __ATOMIC_SEQ_CST,
145  __ATOMIC_SEQ_CST ) )
146  {
147  ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;
148  }
149 
150 #else
151 
152  ATOMIC_ENTER_CRITICAL();
153 
154  if ( *pDestination == ulComparand )
155  {
156  *pDestination = ulExchange;
157  ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;
158  }
159 
160  ATOMIC_EXIT_CRITICAL();
161 
162 #endif
163 
164  return ulReturnValue;
165 
166 }
167 
180 static portFORCE_INLINE void * Atomic_SwapPointers_p32(
181  void * volatile * ppDestination,
182  void * pExchange )
183 {
184  void * pReturnValue;
185 
186 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )
187 
188  __atomic_exchange( ppDestination, &pExchange, &pReturnValue, __ATOMIC_SEQ_CST );
189 
190 #else
191 
192  ATOMIC_ENTER_CRITICAL();
193 
194  pReturnValue = *ppDestination;
195 
196  *ppDestination = pExchange;
197 
198  ATOMIC_EXIT_CRITICAL();
199 
200 #endif
201 
202  return pReturnValue;
203 }
204 
221 static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32(
222  void * volatile * ppDestination,
223  void * pExchange, void * pComparand )
224 {
225  uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE;
226 
227 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )
228  if ( __atomic_compare_exchange( ppDestination,
229  &pComparand,
230  &pExchange,
231  false,
232  __ATOMIC_SEQ_CST,
233  __ATOMIC_SEQ_CST ) )
234  {
235  ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;
236  }
237 
238 #else
239 
240  ATOMIC_ENTER_CRITICAL();
241 
242  if ( *ppDestination == pComparand )
243  {
244  *ppDestination = pExchange;
245  ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;
246  }
247 
248  ATOMIC_EXIT_CRITICAL();
249 
250 #endif
251 
252  return ulReturnValue;
253 }
254 
255 
256 /*----------------------------- Arithmetic ------------------------------*/
257 
269 static portFORCE_INLINE uint32_t Atomic_Add_u32(
270  uint32_t volatile * pAddend,
271  uint32_t ulCount )
272 {
273 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )
274 
275  return __atomic_fetch_add(pAddend, ulCount, __ATOMIC_SEQ_CST);
276 
277 #else
278 
279  uint32_t ulCurrent;
280 
281  ATOMIC_ENTER_CRITICAL();
282 
283  ulCurrent = *pAddend;
284 
285  *pAddend += ulCount;
286 
287  ATOMIC_EXIT_CRITICAL();
288 
289  return ulCurrent;
290 
291 #endif
292 }
293 
306 static portFORCE_INLINE uint32_t Atomic_Subtract_u32(
307  uint32_t volatile * pAddend,
308  uint32_t ulCount )
309 {
310 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )
311 
312  return __atomic_fetch_sub(pAddend, ulCount, __ATOMIC_SEQ_CST);
313 
314 #else
315 
316  uint32_t ulCurrent;
317 
318  ATOMIC_ENTER_CRITICAL();
319 
320  ulCurrent = *pAddend;
321 
322  *pAddend -= ulCount;
323 
324  ATOMIC_EXIT_CRITICAL();
325 
326  return ulCurrent;
327 
328 #endif
329 }
330 
341 static portFORCE_INLINE uint32_t Atomic_Increment_u32( uint32_t volatile * pAddend )
342 {
343 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )
344 
345  return __atomic_fetch_add(pAddend, 1, __ATOMIC_SEQ_CST);
346 
347 #else
348 
349  uint32_t ulCurrent;
350 
351  ATOMIC_ENTER_CRITICAL();
352 
353  ulCurrent = *pAddend;
354 
355  *pAddend += 1;
356 
357  ATOMIC_EXIT_CRITICAL();
358 
359  return ulCurrent;
360 
361 #endif
362 }
363 
374 static portFORCE_INLINE uint32_t Atomic_Decrement_u32( uint32_t volatile * pAddend )
375 {
376 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )
377 
378  return __atomic_fetch_sub(pAddend, 1, __ATOMIC_SEQ_CST);
379 
380 #else
381 
382  uint32_t ulCurrent;
383 
384  ATOMIC_ENTER_CRITICAL();
385 
386  ulCurrent = *pAddend;
387 
388  *pAddend -= 1;
389 
390  ATOMIC_EXIT_CRITICAL();
391 
392  return ulCurrent;
393 
394 #endif
395 }
396 
397 /*----------------------------- Bitwise Logical ------------------------------*/
398 
410 static portFORCE_INLINE uint32_t Atomic_OR_u32(
411  uint32_t volatile * pDestination,
412  uint32_t ulValue )
413 {
414 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )
415 
416  return __atomic_fetch_or(pDestination, ulValue, __ATOMIC_SEQ_CST);
417 
418 #else
419 
420  uint32_t ulCurrent;
421 
422  ATOMIC_ENTER_CRITICAL();
423 
424  ulCurrent = *pDestination;
425 
426  *pDestination |= ulValue;
427 
428  ATOMIC_EXIT_CRITICAL();
429 
430  return ulCurrent;
431 
432 #endif
433 }
434 
446 static portFORCE_INLINE uint32_t Atomic_AND_u32(
447  uint32_t volatile * pDestination,
448  uint32_t ulValue )
449 {
450 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )
451 
452  return __atomic_fetch_and(pDestination, ulValue, __ATOMIC_SEQ_CST);
453 
454 #else
455 
456  uint32_t ulCurrent;
457 
458  ATOMIC_ENTER_CRITICAL();
459 
460  ulCurrent = *pDestination;
461 
462  *pDestination &= ulValue;
463 
464  ATOMIC_EXIT_CRITICAL();
465 
466  return ulCurrent;
467 
468 #endif
469 }
470 
482 static portFORCE_INLINE uint32_t Atomic_NAND_u32(
483  uint32_t volatile * pDestination,
484  uint32_t ulValue )
485 {
486 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )
487 
488  return __atomic_fetch_nand(pDestination, ulValue, __ATOMIC_SEQ_CST);
489 
490 #else
491 
492  uint32_t ulCurrent;
493 
494  ATOMIC_ENTER_CRITICAL();
495 
496  ulCurrent = *pDestination;
497 
498  *pDestination = ~(ulCurrent & ulValue);
499 
500  ATOMIC_EXIT_CRITICAL();
501 
502  return ulCurrent;
503 
504 #endif
505 }
506 
518 static portFORCE_INLINE uint32_t Atomic_XOR_u32(
519  uint32_t volatile * pDestination,
520  uint32_t ulValue )
521 {
522 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )
523 
524  return __atomic_fetch_xor(pDestination, ulValue, __ATOMIC_SEQ_CST);
525 
526 #else
527 
528  uint32_t ulCurrent;
529 
530  ATOMIC_ENTER_CRITICAL();
531 
532  ulCurrent = *pDestination;
533 
534  *pDestination ^= ulValue;
535 
536  ATOMIC_EXIT_CRITICAL();
537 
538  return ulCurrent;
539 
540 #endif
541 }
542 
543 #ifdef __cplusplus
544 }
545 #endif
546 
547 #endif /* ATOMIC_H */
ATOMIC_COMPARE_AND_SWAP_SUCCESS
#define ATOMIC_COMPARE_AND_SWAP_SUCCESS
Definition: atomic.h:110
Atomic_Increment_u32
static portFORCE_INLINE uint32_t Atomic_Increment_u32(uint32_t volatile *pAddend)
Atomically increments the value of the specified pointer points to.
Definition: atomic.h:341
Atomic_CompareAndSwapPointers_p32
static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32(void *volatile *ppDestination, void *pExchange, void *pComparand)
Performs an atomic compare-and-swap operation on the specified pointer values.
Definition: atomic.h:221
Atomic_OR_u32
static portFORCE_INLINE uint32_t Atomic_OR_u32(uint32_t volatile *pDestination, uint32_t ulValue)
Performs an atomic OR operation on the specified values.
Definition: atomic.h:410
Atomic_AND_u32
static portFORCE_INLINE uint32_t Atomic_AND_u32(uint32_t volatile *pDestination, uint32_t ulValue)
Performs an atomic AND operation on the specified values.
Definition: atomic.h:446
Atomic_NAND_u32
static portFORCE_INLINE uint32_t Atomic_NAND_u32(uint32_t volatile *pDestination, uint32_t ulValue)
Performs an atomic NAND operation on the specified values.
Definition: atomic.h:482
Atomic_Decrement_u32
static portFORCE_INLINE uint32_t Atomic_Decrement_u32(uint32_t volatile *pAddend)
Atomically decrements the value of the specified pointer points to.
Definition: atomic.h:374
Atomic_Subtract_u32
static portFORCE_INLINE uint32_t Atomic_Subtract_u32(uint32_t volatile *pAddend, uint32_t ulCount)
Atomically subtracts count from the value of the specified pointer pointers to.
Definition: atomic.h:306
ATOMIC_COMPARE_AND_SWAP_FAILURE
#define ATOMIC_COMPARE_AND_SWAP_FAILURE
Definition: atomic.h:111
Atomic_Add_u32
static portFORCE_INLINE uint32_t Atomic_Add_u32(uint32_t volatile *pAddend, uint32_t ulCount)
Atomically adds count to the value of the specified pointer points to.
Definition: atomic.h:269
Atomic_SwapPointers_p32
static portFORCE_INLINE void * Atomic_SwapPointers_p32(void *volatile *ppDestination, void *pExchange)
Atomically sets the address pointed to by *ppDestination to the value of *pExchange.
Definition: atomic.h:180
Atomic_XOR_u32
static portFORCE_INLINE uint32_t Atomic_XOR_u32(uint32_t volatile *pDestination, uint32_t ulValue)
Performs an atomic XOR operation on the specified values.
Definition: atomic.h:518
Atomic_CompareAndSwap_u32
static portFORCE_INLINE uint32_t Atomic_CompareAndSwap_u32(uint32_t volatile *pDestination, uint32_t ulExchange, uint32_t ulComparand)
Performs an atomic compare-and-swap operation on the specified values.
Definition: atomic.h:130