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