]> begriffs open source - freertos/blob - include/atomic.h
Allow application to override TEX,S,C and B bits for Flash and RAM (#113)
[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  * 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