]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/atomic.h
Correct an err in queue.c introduced when previously updating behaviour when queue...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-IoT-Libraries / c_sdk / standard / common / include / atomic.h
1 /*\r
2  * FreeRTOS Kernel V10.2.0\r
3  * Copyright (C) 2019 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 /**\r
29  * @file atomic.h\r
30  * @brief FreeRTOS atomic operation support.\r
31  *\r
32  * Two implementations of atomic are given in this header file:\r
33  * 1. Disabling interrupt globally.\r
34  * 2. ISA native atomic support.\r
35  * The former is available to all ports (compiler-architecture combination),\r
36  * while the latter is only available to ports compiling with GCC (version at\r
37  * least 4.7.0), which also have ISA atomic support.\r
38  *\r
39  * User can select which implementation to use by:\r
40  * setting/clearing configUSE_ATOMIC_INSTRUCTION in FreeRTOSConfig.h.\r
41  * Define AND set configUSE_ATOMIC_INSTRUCTION to 1 for ISA native atomic support.\r
42  * Undefine OR clear configUSE_ATOMIC_INSTRUCTION for disabling global interrupt\r
43  * implementation.\r
44  *\r
45  * @see GCC Built-in Functions for Memory Model Aware Atomic Operations\r
46  *      https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html\r
47  */\r
48 \r
49 #ifndef ATOMIC_H\r
50 #define ATOMIC_H\r
51 \r
52 #ifndef INC_FREERTOS_H\r
53     #error "include FreeRTOS.h must appear in source files before include atomic.h"\r
54 #endif\r
55 \r
56 /* Standard includes. */\r
57 #include <stdint.h>\r
58 \r
59 #ifdef __cplusplus\r
60 extern "C" {\r
61 #endif\r
62 \r
63 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )\r
64 \r
65     /* Needed for __atomic_compare_exchange() weak=false. */\r
66     #include <stdbool.h>\r
67 \r
68     /* This branch is for GCC compiler and GCC compiler only. */\r
69     #ifndef portFORCE_INLINE\r
70         #define portFORCE_INLINE  inline __attribute__((always_inline))\r
71     #endif\r
72 \r
73 #else\r
74 \r
75     /* Port specific definitions -- entering/exiting critical section.\r
76      * Refer template -- ./lib/FreeRTOS/portable/Compiler/Arch/portmacro.h\r
77      *\r
78      * Every call to ATOMIC_EXIT_CRITICAL() must be closely paired with\r
79      * ATOMIC_ENTER_CRITICAL().\r
80      */\r
81     #if defined( portSET_INTERRUPT_MASK_FROM_ISR )\r
82 \r
83         /* Nested interrupt scheme is supported in this port. */\r
84         #define ATOMIC_ENTER_CRITICAL()     \\r
85             UBaseType_t uxCriticalSectionType = portSET_INTERRUPT_MASK_FROM_ISR()\r
86 \r
87         #define ATOMIC_EXIT_CRITICAL()      \\r
88             portCLEAR_INTERRUPT_MASK_FROM_ISR( uxCriticalSectionType )\r
89 \r
90     #else\r
91 \r
92         /* Nested interrupt scheme is NOT supported in this port. */\r
93         #define ATOMIC_ENTER_CRITICAL()     portENTER_CRITICAL()\r
94         #define ATOMIC_EXIT_CRITICAL()      portEXIT_CRITICAL()\r
95 \r
96     #endif /* portSET_INTERRUPT_MASK_FROM_ISR() */\r
97 \r
98     /* Port specific definition -- "always inline". \r
99      * Inline is compiler specific, and may not always get inlined depending on your optimization level. \r
100      * Also, inline is considerred as performance optimization for atomic. \r
101      * Thus, if portFORCE_INLINE is not provided by portmacro.h, instead of resulting error,\r
102      * simply define it. \r
103      */\r
104     #ifndef portFORCE_INLINE\r
105         #define portFORCE_INLINE \r
106     #endif\r
107 \r
108 #endif /* configUSE_GCC_BUILTIN_ATOMICS */\r
109 \r
110 #define ATOMIC_COMPARE_AND_SWAP_SUCCESS     0x1U        /**< Compare and swap succeeded, swapped. */\r
111 #define ATOMIC_COMPARE_AND_SWAP_FAILURE     0x0U        /**< Compare and swap failed, did not swap. */\r
112 \r
113 /*----------------------------- Swap && CAS ------------------------------*/\r
114 \r
115 /**\r
116  * Atomic compare-and-swap\r
117  *\r
118  * @brief Performs an atomic compare-and-swap operation on the specified values.\r
119  *\r
120  * @param[in, out] pDestination  Pointer to memory location from where value is\r
121  *                               to be loaded and checked.\r
122  * @param[in] ulExchange         If condition meets, write this value to memory.\r
123  * @param[in] ulComparand        Swap condition.\r
124  *\r
125  * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped.\r
126  *\r
127  * @note This function only swaps *pDestination with ulExchange, if previous\r
128  *       *pDestination value equals ulComparand.\r
129  */\r
130 static portFORCE_INLINE uint32_t Atomic_CompareAndSwap_u32(\r
131         uint32_t volatile * pDestination,\r
132         uint32_t ulExchange,\r
133         uint32_t ulComparand )\r
134 {\r
135 \r
136     uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE;\r
137 \r
138 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )\r
139 \r
140     if ( __atomic_compare_exchange( pDestination,\r
141                                     &ulComparand,\r
142                                     &ulExchange,\r
143                                     false,\r
144                                     __ATOMIC_SEQ_CST,\r
145                                     __ATOMIC_SEQ_CST ) )\r
146     {\r
147         ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;\r
148     }\r
149 \r
150 #else\r
151 \r
152     ATOMIC_ENTER_CRITICAL();\r
153 \r
154     if ( *pDestination == ulComparand )\r
155     {\r
156         *pDestination = ulExchange;\r
157         ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;\r
158     }\r
159 \r
160     ATOMIC_EXIT_CRITICAL();\r
161 \r
162 #endif\r
163 \r
164     return ulReturnValue;\r
165 \r
166 }\r
167 \r
168 /**\r
169  * Atomic swap (pointers)\r
170  *\r
171  * @brief Atomically sets the address pointed to by *ppDestination to the value\r
172  *        of *pExchange.\r
173  *\r
174  * @param[in, out] ppDestination  Pointer to memory location from where a pointer\r
175  *                                value is to be loaded and written back to.\r
176  * @param[in] pExchange           Pointer value to be written to *ppDestination.\r
177  *\r
178  * @return The initial value of *ppDestination.\r
179  */\r
180 static portFORCE_INLINE void * Atomic_SwapPointers_p32(\r
181         void * volatile * ppDestination,\r
182         void * pExchange )\r
183 {\r
184     void * pReturnValue;\r
185 \r
186 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )\r
187 \r
188     __atomic_exchange( ppDestination, &pExchange, &pReturnValue, __ATOMIC_SEQ_CST );\r
189 \r
190 #else\r
191 \r
192     ATOMIC_ENTER_CRITICAL();\r
193 \r
194     pReturnValue = *ppDestination;\r
195 \r
196     *ppDestination = pExchange;\r
197 \r
198     ATOMIC_EXIT_CRITICAL();\r
199 \r
200 #endif\r
201 \r
202     return pReturnValue;\r
203 }\r
204 \r
205 /**\r
206  * Atomic compare-and-swap (pointers)\r
207  *\r
208  * @brief Performs an atomic compare-and-swap operation on the specified pointer\r
209  *        values.\r
210  *\r
211  * @param[in, out] ppDestination  Pointer to memory location from where a pointer\r
212  *                                value is to be loaded and checked.\r
213  * @param[in] pExchange           If condition meets, write this value to memory.\r
214  * @param[in] pComparand          Swap condition.\r
215  *\r
216  * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped.\r
217  *\r
218  * @note This function only swaps *ppDestination with pExchange, if previous\r
219  *       *ppDestination value equals pComparand.\r
220  */\r
221 static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32(\r
222         void * volatile * ppDestination,\r
223         void * pExchange, void * pComparand )\r
224 {\r
225     uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE;\r
226 \r
227 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )\r
228     if ( __atomic_compare_exchange( ppDestination,\r
229                                     &pComparand,\r
230                                     &pExchange,\r
231                                     false,\r
232                                     __ATOMIC_SEQ_CST,\r
233                                     __ATOMIC_SEQ_CST ) )\r
234     {\r
235         ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;\r
236     }\r
237 \r
238 #else\r
239 \r
240     ATOMIC_ENTER_CRITICAL();\r
241 \r
242     if ( *ppDestination == pComparand )\r
243     {\r
244         *ppDestination = pExchange;\r
245         ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;\r
246     }\r
247 \r
248     ATOMIC_EXIT_CRITICAL();\r
249 \r
250 #endif\r
251 \r
252     return ulReturnValue;\r
253 }\r
254 \r
255 \r
256 /*----------------------------- Arithmetic ------------------------------*/\r
257 \r
258 /**\r
259  * Atomic add\r
260  *\r
261  * @brief Atomically adds count to the value of the specified pointer points to.\r
262  *\r
263  * @param[in,out] pAddend  Pointer to memory location from where value is to be\r
264  *                         loaded and written back to.\r
265  * @param[in] ulCount      Value to be added to *pAddend.\r
266  *\r
267  * @return previous *pAddend value.\r
268  */\r
269 static portFORCE_INLINE uint32_t Atomic_Add_u32(\r
270         uint32_t volatile * pAddend,\r
271         uint32_t ulCount )\r
272 {\r
273 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )\r
274 \r
275     return __atomic_fetch_add(pAddend, ulCount, __ATOMIC_SEQ_CST);\r
276 \r
277 #else\r
278 \r
279     uint32_t ulCurrent;\r
280 \r
281     ATOMIC_ENTER_CRITICAL();\r
282 \r
283     ulCurrent = *pAddend;\r
284 \r
285     *pAddend += ulCount;\r
286 \r
287     ATOMIC_EXIT_CRITICAL();\r
288 \r
289     return ulCurrent;\r
290 \r
291 #endif\r
292 }\r
293 \r
294 /**\r
295  * Atomic subtract\r
296  *\r
297  * @brief Atomically subtracts count from the value of the specified pointer\r
298  *        pointers to.\r
299  *\r
300  * @param[in,out] pAddend  Pointer to memory location from where value is to be\r
301  *                         loaded and written back to.\r
302  * @param[in] ulCount      Value to be subtract from *pAddend.\r
303  *\r
304  * @return previous *pAddend value.\r
305  */\r
306 static portFORCE_INLINE uint32_t Atomic_Subtract_u32(\r
307         uint32_t volatile * pAddend,\r
308         uint32_t ulCount )\r
309 {\r
310 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )\r
311 \r
312     return __atomic_fetch_sub(pAddend, ulCount, __ATOMIC_SEQ_CST);\r
313 \r
314 #else\r
315 \r
316     uint32_t ulCurrent;\r
317 \r
318     ATOMIC_ENTER_CRITICAL();\r
319 \r
320     ulCurrent = *pAddend;\r
321 \r
322     *pAddend -= ulCount;\r
323 \r
324     ATOMIC_EXIT_CRITICAL();\r
325 \r
326     return ulCurrent;\r
327 \r
328 #endif\r
329 }\r
330 \r
331 /**\r
332  * Atomic increment\r
333  *\r
334  * @brief Atomically increments the value of the specified pointer points to.\r
335  *\r
336  * @param[in,out] pAddend  Pointer to memory location from where value is to be\r
337  *                         loaded and written back to.\r
338  *\r
339  * @return *pAddend value before increment.\r
340  */\r
341 static portFORCE_INLINE uint32_t Atomic_Increment_u32( uint32_t volatile * pAddend )\r
342 {\r
343 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )\r
344 \r
345     return __atomic_fetch_add(pAddend, 1, __ATOMIC_SEQ_CST);\r
346 \r
347 #else\r
348 \r
349     uint32_t ulCurrent;\r
350 \r
351     ATOMIC_ENTER_CRITICAL();\r
352 \r
353     ulCurrent = *pAddend;\r
354 \r
355     *pAddend += 1;\r
356 \r
357     ATOMIC_EXIT_CRITICAL();\r
358 \r
359     return ulCurrent;\r
360 \r
361 #endif\r
362 }\r
363 \r
364 /**\r
365  * Atomic decrement\r
366  *\r
367  * @brief Atomically decrements the value of the specified pointer points to\r
368  *\r
369  * @param[in,out] pAddend  Pointer to memory location from where value is to be\r
370  *                         loaded and written back to.\r
371  *\r
372  * @return *pAddend value before decrement.\r
373  */\r
374 static portFORCE_INLINE uint32_t Atomic_Decrement_u32( uint32_t volatile * pAddend )\r
375 {\r
376 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )\r
377 \r
378     return __atomic_fetch_sub(pAddend, 1, __ATOMIC_SEQ_CST);\r
379 \r
380 #else\r
381 \r
382     uint32_t ulCurrent;\r
383 \r
384     ATOMIC_ENTER_CRITICAL();\r
385 \r
386     ulCurrent = *pAddend;\r
387 \r
388     *pAddend -= 1;\r
389 \r
390     ATOMIC_EXIT_CRITICAL();\r
391 \r
392     return ulCurrent;\r
393 \r
394 #endif\r
395 }\r
396 \r
397 /*----------------------------- Bitwise Logical ------------------------------*/\r
398 \r
399 /**\r
400  * Atomic OR\r
401  *\r
402  * @brief Performs an atomic OR operation on the specified values.\r
403  *\r
404  * @param [in, out] pDestination  Pointer to memory location from where value is\r
405  *                                to be loaded and written back to.\r
406  * @param [in] ulValue            Value to be ORed with *pDestination.\r
407  *\r
408  * @return The original value of *pDestination.\r
409  */\r
410 static portFORCE_INLINE uint32_t Atomic_OR_u32(\r
411         uint32_t volatile * pDestination,\r
412         uint32_t ulValue )\r
413 {\r
414 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )\r
415 \r
416     return __atomic_fetch_or(pDestination, ulValue, __ATOMIC_SEQ_CST);\r
417 \r
418 #else\r
419 \r
420     uint32_t ulCurrent;\r
421 \r
422     ATOMIC_ENTER_CRITICAL();\r
423 \r
424     ulCurrent = *pDestination;\r
425 \r
426     *pDestination |= ulValue;\r
427 \r
428     ATOMIC_EXIT_CRITICAL();\r
429 \r
430     return ulCurrent;\r
431 \r
432 #endif\r
433 }\r
434 \r
435 /**\r
436  * Atomic AND\r
437  *\r
438  * @brief Performs an atomic AND operation on the specified values.\r
439  *\r
440  * @param [in, out] pDestination  Pointer to memory location from where value is\r
441  *                                to be loaded and written back to.\r
442  * @param [in] ulValue            Value to be ANDed with *pDestination.\r
443  *\r
444  * @return The original value of *pDestination.\r
445  */\r
446 static portFORCE_INLINE uint32_t Atomic_AND_u32(\r
447         uint32_t volatile * pDestination,\r
448         uint32_t ulValue )\r
449 {\r
450 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )\r
451 \r
452     return __atomic_fetch_and(pDestination, ulValue, __ATOMIC_SEQ_CST);\r
453 \r
454 #else\r
455 \r
456     uint32_t ulCurrent;\r
457 \r
458     ATOMIC_ENTER_CRITICAL();\r
459 \r
460     ulCurrent = *pDestination;\r
461 \r
462     *pDestination &= ulValue;\r
463 \r
464     ATOMIC_EXIT_CRITICAL();\r
465 \r
466     return ulCurrent;\r
467 \r
468 #endif\r
469 }\r
470 \r
471 /**\r
472  * Atomic NAND\r
473  *\r
474  * @brief Performs an atomic NAND operation on the specified values.\r
475  *\r
476  * @param [in, out] pDestination  Pointer to memory location from where value is\r
477  *                                to be loaded and written back to.\r
478  * @param [in] ulValue            Value to be NANDed with *pDestination.\r
479  *\r
480  * @return The original value of *pDestination.\r
481  */\r
482 static portFORCE_INLINE uint32_t Atomic_NAND_u32(\r
483         uint32_t volatile * pDestination,\r
484         uint32_t ulValue )\r
485 {\r
486 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )\r
487 \r
488     return __atomic_fetch_nand(pDestination, ulValue, __ATOMIC_SEQ_CST);\r
489 \r
490 #else\r
491 \r
492     uint32_t ulCurrent;\r
493 \r
494     ATOMIC_ENTER_CRITICAL();\r
495 \r
496     ulCurrent = *pDestination;\r
497 \r
498     *pDestination = ~(ulCurrent & ulValue);\r
499 \r
500     ATOMIC_EXIT_CRITICAL();\r
501 \r
502     return ulCurrent;\r
503 \r
504 #endif\r
505 }\r
506 \r
507 /**\r
508  * Atomic XOR\r
509  *\r
510  * @brief Performs an atomic XOR operation on the specified values.\r
511  *\r
512  * @param [in, out] pDestination  Pointer to memory location from where value is\r
513  *                                to be loaded and written back to.\r
514  * @param [in] ulValue            Value to be XORed with *pDestination.\r
515  *\r
516  * @return The original value of *pDestination.\r
517  */\r
518 static portFORCE_INLINE uint32_t Atomic_XOR_u32(\r
519         uint32_t volatile * pDestination,\r
520         uint32_t ulValue )\r
521 {\r
522 #if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 )\r
523 \r
524     return __atomic_fetch_xor(pDestination, ulValue, __ATOMIC_SEQ_CST);\r
525 \r
526 #else\r
527 \r
528     uint32_t ulCurrent;\r
529 \r
530     ATOMIC_ENTER_CRITICAL();\r
531 \r
532     ulCurrent = *pDestination;\r
533 \r
534     *pDestination ^= ulValue;\r
535 \r
536     ATOMIC_EXIT_CRITICAL();\r
537 \r
538     return ulCurrent;\r
539 \r
540 #endif\r
541 }\r
542 \r
543 #ifdef __cplusplus\r
544 }\r
545 #endif\r
546 \r
547 #endif /* ATOMIC_H */\r