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