]> git.sur5r.net Git - freertos/blob - FreeRTOS/Source/include/atomic.h
Update to the latest atomic.h.
[freertos] / FreeRTOS / Source / include / atomic.h
1 /*\r
2  * FreeRTOS Kernel V10.2.1\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  * This file implements atomic functions by disabling interrupts globally.\r
33  * Implementations with architecture specific atomic instructions can be\r
34  * provided under each compiler directory.\r
35  */\r
36 \r
37 #ifndef ATOMIC_H\r
38 #define ATOMIC_H\r
39 \r
40 #ifndef INC_FREERTOS_H\r
41         #error "include FreeRTOS.h must appear in source files before include atomic.h"\r
42 #endif\r
43 \r
44 /* Standard includes. */\r
45 #include <stdint.h>\r
46 \r
47 #ifdef __cplusplus\r
48 extern "C" {\r
49 #endif\r
50 \r
51 /*\r
52  * Port specific definitions -- entering/exiting critical section.\r
53  * Refer template -- ./lib/FreeRTOS/portable/Compiler/Arch/portmacro.h\r
54  *\r
55  * Every call to ATOMIC_EXIT_CRITICAL() must be closely paired with\r
56  * ATOMIC_ENTER_CRITICAL().\r
57  *\r
58  */\r
59 #if defined( portSET_INTERRUPT_MASK_FROM_ISR )\r
60 \r
61         /* Nested interrupt scheme is supported in this port. */\r
62         #define ATOMIC_ENTER_CRITICAL()  \\r
63                 UBaseType_t uxCriticalSectionType = portSET_INTERRUPT_MASK_FROM_ISR()\r
64 \r
65         #define ATOMIC_EXIT_CRITICAL()    \\r
66                 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxCriticalSectionType )\r
67 \r
68 #else\r
69 \r
70         /* Nested interrupt scheme is NOT supported in this port. */\r
71         #define ATOMIC_ENTER_CRITICAL()  portENTER_CRITICAL()\r
72         #define ATOMIC_EXIT_CRITICAL()    portEXIT_CRITICAL()\r
73 \r
74 #endif /* portSET_INTERRUPT_MASK_FROM_ISR() */\r
75 \r
76 /*\r
77  * Port specific definition -- "always inline".\r
78  * Inline is compiler specific, and may not always get inlined depending on your\r
79  * optimization level.  Also, inline is considered as performance optimization\r
80  * for atomic.  Thus, if portFORCE_INLINE is not provided by portmacro.h,\r
81  * instead of resulting error, simply define it away.\r
82  */\r
83 #ifndef portFORCE_INLINE\r
84         #define portFORCE_INLINE\r
85 #endif\r
86 \r
87 #define ATOMIC_COMPARE_AND_SWAP_SUCCESS  0x1U           /**< Compare and swap succeeded, swapped. */\r
88 #define ATOMIC_COMPARE_AND_SWAP_FAILURE  0x0U           /**< Compare and swap failed, did not swap. */\r
89 \r
90 /*----------------------------- Swap && CAS ------------------------------*/\r
91 \r
92 /**\r
93  * Atomic compare-and-swap\r
94  *\r
95  * @brief Performs an atomic compare-and-swap operation on the specified values.\r
96  *\r
97  * @param[in, out] pulDestination  Pointer to memory location from where value is\r
98  *                               to be loaded and checked.\r
99  * @param[in] ulExchange         If condition meets, write this value to memory.\r
100  * @param[in] ulComparand        Swap condition.\r
101  *\r
102  * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped.\r
103  *\r
104  * @note This function only swaps *pulDestination with ulExchange, if previous\r
105  *       *pulDestination value equals ulComparand.\r
106  */\r
107 static portFORCE_INLINE uint32_t Atomic_CompareAndSwap_u32( uint32_t volatile * pulDestination,\r
108                                                                                                                         uint32_t ulExchange,\r
109                                                                                                                         uint32_t ulComparand )\r
110 {\r
111 uint32_t ulReturnValue;\r
112 \r
113         ATOMIC_ENTER_CRITICAL();\r
114         {\r
115                 if( *pulDestination == ulComparand )\r
116                 {\r
117                         *pulDestination = ulExchange;\r
118                         ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;\r
119                 }\r
120                 else\r
121                 {\r
122                         ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE;\r
123                 }\r
124         }\r
125         ATOMIC_EXIT_CRITICAL();\r
126 \r
127         return ulReturnValue;\r
128 }\r
129 /*-----------------------------------------------------------*/\r
130 \r
131 /**\r
132  * Atomic swap (pointers)\r
133  *\r
134  * @brief Atomically sets the address pointed to by *ppvDestination to the value\r
135  *        of *pvExchange.\r
136  *\r
137  * @param[in, out] ppvDestination  Pointer to memory location from where a pointer\r
138  *                                 value is to be loaded and written back to.\r
139  * @param[in] pvExchange           Pointer value to be written to *ppvDestination.\r
140  *\r
141  * @return The initial value of *ppvDestination.\r
142  */\r
143 static portFORCE_INLINE void * Atomic_SwapPointers_p32( void * volatile * ppvDestination,\r
144                                                                                                                 void * pvExchange )\r
145 {\r
146 void * pReturnValue;\r
147 \r
148         ATOMIC_ENTER_CRITICAL();\r
149         {\r
150                 pReturnValue = *ppvDestination;\r
151                 *ppvDestination = pvExchange;\r
152         }\r
153         ATOMIC_EXIT_CRITICAL();\r
154 \r
155         return pReturnValue;\r
156 }\r
157 /*-----------------------------------------------------------*/\r
158 \r
159 /**\r
160  * Atomic compare-and-swap (pointers)\r
161  *\r
162  * @brief Performs an atomic compare-and-swap operation on the specified pointer\r
163  *        values.\r
164  *\r
165  * @param[in, out] ppvDestination  Pointer to memory location from where a pointer\r
166  *                                 value is to be loaded and checked.\r
167  * @param[in] pvExchange           If condition meets, write this value to memory.\r
168  * @param[in] pvComparand          Swap condition.\r
169  *\r
170  * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped.\r
171  *\r
172  * @note This function only swaps *ppvDestination with pvExchange, if previous\r
173  *       *ppvDestination value equals pvComparand.\r
174  */\r
175 static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32( void * volatile * ppvDestination,\r
176                                                                                                                                         void * pvExchange,\r
177                                                                                                                                         void * pvComparand )\r
178 {\r
179 uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE;\r
180 \r
181         ATOMIC_ENTER_CRITICAL();\r
182         {\r
183                 if( *ppvDestination == pvComparand )\r
184                 {\r
185                         *ppvDestination = pvExchange;\r
186                         ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;\r
187                 }\r
188         }\r
189         ATOMIC_EXIT_CRITICAL();\r
190 \r
191         return ulReturnValue;\r
192 }\r
193 \r
194 \r
195 /*----------------------------- Arithmetic ------------------------------*/\r
196 \r
197 /**\r
198  * Atomic add\r
199  *\r
200  * @brief Atomically adds count to the value of the specified pointer points to.\r
201  *\r
202  * @param[in,out] pulAddend  Pointer to memory location from where value is to be\r
203  *                         loaded and written back to.\r
204  * @param[in] ulCount      Value to be added to *pulAddend.\r
205  *\r
206  * @return previous *pulAddend value.\r
207  */\r
208 static portFORCE_INLINE uint32_t Atomic_Add_u32( uint32_t volatile * pulAddend,\r
209                                                                                                  uint32_t ulCount )\r
210 {\r
211         uint32_t ulCurrent;\r
212 \r
213         ATOMIC_ENTER_CRITICAL();\r
214         {\r
215                 ulCurrent = *pulAddend;\r
216                 *pulAddend += ulCount;\r
217         }\r
218         ATOMIC_EXIT_CRITICAL();\r
219 \r
220         return ulCurrent;\r
221 }\r
222 /*-----------------------------------------------------------*/\r
223 \r
224 /**\r
225  * Atomic subtract\r
226  *\r
227  * @brief Atomically subtracts count from the value of the specified pointer\r
228  *        pointers to.\r
229  *\r
230  * @param[in,out] pulAddend  Pointer to memory location from where value is to be\r
231  *                         loaded and written back to.\r
232  * @param[in] ulCount      Value to be subtract from *pulAddend.\r
233  *\r
234  * @return previous *pulAddend value.\r
235  */\r
236 static portFORCE_INLINE uint32_t Atomic_Subtract_u32( uint32_t volatile * pulAddend,\r
237                                                                                                           uint32_t ulCount )\r
238 {\r
239         uint32_t ulCurrent;\r
240 \r
241         ATOMIC_ENTER_CRITICAL();\r
242         {\r
243                 ulCurrent = *pulAddend;\r
244                 *pulAddend -= ulCount;\r
245         }\r
246         ATOMIC_EXIT_CRITICAL();\r
247 \r
248         return ulCurrent;\r
249 }\r
250 /*-----------------------------------------------------------*/\r
251 \r
252 /**\r
253  * Atomic increment\r
254  *\r
255  * @brief Atomically increments the value of the specified pointer points to.\r
256  *\r
257  * @param[in,out] pulAddend  Pointer to memory location from where value is to be\r
258  *                         loaded and written back to.\r
259  *\r
260  * @return *pulAddend value before increment.\r
261  */\r
262 static portFORCE_INLINE uint32_t Atomic_Increment_u32( uint32_t volatile * pulAddend )\r
263 {\r
264 uint32_t ulCurrent;\r
265 \r
266         ATOMIC_ENTER_CRITICAL();\r
267         {\r
268                 ulCurrent = *pulAddend;\r
269                 *pulAddend += 1;\r
270         }\r
271         ATOMIC_EXIT_CRITICAL();\r
272 \r
273         return ulCurrent;\r
274 }\r
275 /*-----------------------------------------------------------*/\r
276 \r
277 /**\r
278  * Atomic decrement\r
279  *\r
280  * @brief Atomically decrements the value of the specified pointer points to\r
281  *\r
282  * @param[in,out] pulAddend  Pointer to memory location from where value is to be\r
283  *                         loaded and written back to.\r
284  *\r
285  * @return *pulAddend value before decrement.\r
286  */\r
287 static portFORCE_INLINE uint32_t Atomic_Decrement_u32( uint32_t volatile * pulAddend )\r
288 {\r
289 uint32_t ulCurrent;\r
290 \r
291         ATOMIC_ENTER_CRITICAL();\r
292         {\r
293                 ulCurrent = *pulAddend;\r
294                 *pulAddend -= 1;\r
295         }\r
296         ATOMIC_EXIT_CRITICAL();\r
297 \r
298         return ulCurrent;\r
299 }\r
300 \r
301 /*----------------------------- Bitwise Logical ------------------------------*/\r
302 \r
303 /**\r
304  * Atomic OR\r
305  *\r
306  * @brief Performs an atomic OR operation on the specified values.\r
307  *\r
308  * @param [in, out] pulDestination  Pointer to memory location from where value is\r
309  *                                to be loaded and written back to.\r
310  * @param [in] ulValue            Value to be ORed with *pulDestination.\r
311  *\r
312  * @return The original value of *pulDestination.\r
313  */\r
314 static portFORCE_INLINE uint32_t Atomic_OR_u32( uint32_t volatile * pulDestination,\r
315                                                                                                 uint32_t ulValue )\r
316 {\r
317 uint32_t ulCurrent;\r
318 \r
319         ATOMIC_ENTER_CRITICAL();\r
320         {\r
321                 ulCurrent = *pulDestination;\r
322                 *pulDestination |= ulValue;\r
323         }\r
324         ATOMIC_EXIT_CRITICAL();\r
325 \r
326         return ulCurrent;\r
327 }\r
328 /*-----------------------------------------------------------*/\r
329 \r
330 /**\r
331  * Atomic AND\r
332  *\r
333  * @brief Performs an atomic AND operation on the specified values.\r
334  *\r
335  * @param [in, out] pulDestination  Pointer to memory location from where value is\r
336  *                                to be loaded and written back to.\r
337  * @param [in] ulValue            Value to be ANDed with *pulDestination.\r
338  *\r
339  * @return The original value of *pulDestination.\r
340  */\r
341 static portFORCE_INLINE uint32_t Atomic_AND_u32( uint32_t volatile * pulDestination,\r
342                                                                                                  uint32_t ulValue )\r
343 {\r
344 uint32_t ulCurrent;\r
345 \r
346         ATOMIC_ENTER_CRITICAL();\r
347         {\r
348                 ulCurrent = *pulDestination;\r
349                 *pulDestination &= ulValue;\r
350         }\r
351         ATOMIC_EXIT_CRITICAL();\r
352 \r
353         return ulCurrent;\r
354 }\r
355 /*-----------------------------------------------------------*/\r
356 \r
357 /**\r
358  * Atomic NAND\r
359  *\r
360  * @brief Performs an atomic NAND operation on the specified values.\r
361  *\r
362  * @param [in, out] pulDestination  Pointer to memory location from where value is\r
363  *                                to be loaded and written back to.\r
364  * @param [in] ulValue            Value to be NANDed with *pulDestination.\r
365  *\r
366  * @return The original value of *pulDestination.\r
367  */\r
368 static portFORCE_INLINE uint32_t Atomic_NAND_u32( uint32_t volatile * pulDestination,\r
369                                                                                                   uint32_t ulValue )\r
370 {\r
371 uint32_t ulCurrent;\r
372 \r
373         ATOMIC_ENTER_CRITICAL();\r
374         {\r
375                 ulCurrent = *pulDestination;\r
376                 *pulDestination = ~( ulCurrent & ulValue );\r
377         }\r
378         ATOMIC_EXIT_CRITICAL();\r
379 \r
380         return ulCurrent;\r
381 }\r
382 /*-----------------------------------------------------------*/\r
383 \r
384 /**\r
385  * Atomic XOR\r
386  *\r
387  * @brief Performs an atomic XOR operation on the specified values.\r
388  *\r
389  * @param [in, out] pulDestination  Pointer to memory location from where value is\r
390  *                                to be loaded and written back to.\r
391  * @param [in] ulValue            Value to be XORed with *pulDestination.\r
392  *\r
393  * @return The original value of *pulDestination.\r
394  */\r
395 static portFORCE_INLINE uint32_t Atomic_XOR_u32( uint32_t volatile * pulDestination,\r
396                                                                                                  uint32_t ulValue )\r
397 {\r
398 uint32_t ulCurrent;\r
399 \r
400         ATOMIC_ENTER_CRITICAL();\r
401         {\r
402                 ulCurrent = *pulDestination;\r
403                 *pulDestination ^= ulValue;\r
404         }\r
405         ATOMIC_EXIT_CRITICAL();\r
406 \r
407         return ulCurrent;\r
408 }\r
409 \r
410 #ifdef __cplusplus\r
411 }\r
412 #endif\r
413 \r
414 #endif /* ATOMIC_H */\r