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