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