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