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