Skip to content

Commit 47e2e09

Browse files
committed
Merge pull request #1843 from c1728p9/atomic_access
Add functions for atomic access
2 parents d1ec4be + f3b1d45 commit 47e2e09

File tree

2 files changed

+423
-0
lines changed

2 files changed

+423
-0
lines changed

hal/api/critical.h

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#ifndef __MBED_UTIL_CRITICAL_H__
1919
#define __MBED_UTIL_CRITICAL_H__
2020

21+
#include <stdbool.h>
22+
2123
#ifdef __cplusplus
2224
extern "C" {
2325
#endif
@@ -48,6 +50,213 @@ void core_util_critical_section_enter();
4850
*/
4951
void core_util_critical_section_exit();
5052

53+
/**
54+
* Atomic compare and set. It compares the contents of a memory location to a
55+
* given value and, only if they are the same, modifies the contents of that
56+
* memory location to a given new value. This is done as a single atomic
57+
* operation. The atomicity guarantees that the new value is calculated based on
58+
* up-to-date information; if the value had been updated by another thread in
59+
* the meantime, the write would fail due to a mismatched expectedCurrentValue.
60+
*
61+
* Refer to https://en.wikipedia.org/wiki/Compare-and-set [which may redirect
62+
* you to the article on compare-and swap].
63+
*
64+
* @param ptr The target memory location.
65+
* @param[in,out] expectedCurrentValue A pointer to some location holding the
66+
* expected current value of the data being set atomically.
67+
* The computed 'desiredValue' should be a function of this current value.
68+
* @Note: This is an in-out parameter. In the
69+
* failure case of atomic_cas (where the
70+
* destination isn't set), the pointee of expectedCurrentValue is
71+
* updated with the current value.
72+
* @param[in] desiredValue The new value computed based on '*expectedCurrentValue'.
73+
*
74+
* @return true if the memory location was atomically
75+
* updated with the desired value (after verifying
76+
* that it contained the expectedCurrentValue),
77+
* false otherwise. In the failure case,
78+
* exepctedCurrentValue is updated with the new
79+
* value of the target memory location.
80+
*
81+
* pseudocode:
82+
* function cas(p : pointer to int, old : pointer to int, new : int) returns bool {
83+
* if *p != *old {
84+
* *old = *p
85+
* return false
86+
* }
87+
* *p = new
88+
* return true
89+
* }
90+
*
91+
* @Note: In the failure case (where the destination isn't set), the value
92+
* pointed to by expectedCurrentValue is still updated with the current value.
93+
* This property helps writing concise code for the following incr:
94+
*
95+
* function incr(p : pointer to int, a : int) returns int {
96+
* done = false
97+
* *value = *p // This fetch operation need not be atomic.
98+
* while not done {
99+
* done = atomic_cas(p, &value, value + a) // *value gets updated automatically until success
100+
* }
101+
* return value + a
102+
* }
103+
*/
104+
bool core_util_atomic_cas_u8(uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_t desiredValue);
105+
106+
/**
107+
* Atomic compare and set. It compares the contents of a memory location to a
108+
* given value and, only if they are the same, modifies the contents of that
109+
* memory location to a given new value. This is done as a single atomic
110+
* operation. The atomicity guarantees that the new value is calculated based on
111+
* up-to-date information; if the value had been updated by another thread in
112+
* the meantime, the write would fail due to a mismatched expectedCurrentValue.
113+
*
114+
* Refer to https://en.wikipedia.org/wiki/Compare-and-set [which may redirect
115+
* you to the article on compare-and swap].
116+
*
117+
* @param ptr The target memory location.
118+
* @param[in,out] expectedCurrentValue A pointer to some location holding the
119+
* expected current value of the data being set atomically.
120+
* The computed 'desiredValue' should be a function of this current value.
121+
* @Note: This is an in-out parameter. In the
122+
* failure case of atomic_cas (where the
123+
* destination isn't set), the pointee of expectedCurrentValue is
124+
* updated with the current value.
125+
* @param[in] desiredValue The new value computed based on '*expectedCurrentValue'.
126+
*
127+
* @return true if the memory location was atomically
128+
* updated with the desired value (after verifying
129+
* that it contained the expectedCurrentValue),
130+
* false otherwise. In the failure case,
131+
* exepctedCurrentValue is updated with the new
132+
* value of the target memory location.
133+
*
134+
* pseudocode:
135+
* function cas(p : pointer to int, old : pointer to int, new : int) returns bool {
136+
* if *p != *old {
137+
* *old = *p
138+
* return false
139+
* }
140+
* *p = new
141+
* return true
142+
* }
143+
*
144+
* @Note: In the failure case (where the destination isn't set), the value
145+
* pointed to by expectedCurrentValue is still updated with the current value.
146+
* This property helps writing concise code for the following incr:
147+
*
148+
* function incr(p : pointer to int, a : int) returns int {
149+
* done = false
150+
* *value = *p // This fetch operation need not be atomic.
151+
* while not done {
152+
* done = atomic_cas(p, &value, value + a) // *value gets updated automatically until success
153+
* }
154+
* return value + a
155+
* }
156+
*/
157+
bool core_util_atomic_cas_u16(uint16_t *ptr, uint16_t *expectedCurrentValue, uint16_t desiredValue);
158+
159+
/**
160+
* Atomic compare and set. It compares the contents of a memory location to a
161+
* given value and, only if they are the same, modifies the contents of that
162+
* memory location to a given new value. This is done as a single atomic
163+
* operation. The atomicity guarantees that the new value is calculated based on
164+
* up-to-date information; if the value had been updated by another thread in
165+
* the meantime, the write would fail due to a mismatched expectedCurrentValue.
166+
*
167+
* Refer to https://en.wikipedia.org/wiki/Compare-and-set [which may redirect
168+
* you to the article on compare-and swap].
169+
*
170+
* @param ptr The target memory location.
171+
* @param[in,out] expectedCurrentValue A pointer to some location holding the
172+
* expected current value of the data being set atomically.
173+
* The computed 'desiredValue' should be a function of this current value.
174+
* @Note: This is an in-out parameter. In the
175+
* failure case of atomic_cas (where the
176+
* destination isn't set), the pointee of expectedCurrentValue is
177+
* updated with the current value.
178+
* @param[in] desiredValue The new value computed based on '*expectedCurrentValue'.
179+
*
180+
* @return true if the memory location was atomically
181+
* updated with the desired value (after verifying
182+
* that it contained the expectedCurrentValue),
183+
* false otherwise. In the failure case,
184+
* exepctedCurrentValue is updated with the new
185+
* value of the target memory location.
186+
*
187+
* pseudocode:
188+
* function cas(p : pointer to int, old : pointer to int, new : int) returns bool {
189+
* if *p != *old {
190+
* *old = *p
191+
* return false
192+
* }
193+
* *p = new
194+
* return true
195+
* }
196+
*
197+
* @Note: In the failure case (where the destination isn't set), the value
198+
* pointed to by expectedCurrentValue is still updated with the current value.
199+
* This property helps writing concise code for the following incr:
200+
*
201+
* function incr(p : pointer to int, a : int) returns int {
202+
* done = false
203+
* *value = *p // This fetch operation need not be atomic.
204+
* while not done {
205+
* done = atomic_cas(p, &value, value + a) // *value gets updated automatically until success
206+
* }
207+
* return value + a
208+
* }
209+
*/
210+
bool core_util_atomic_cas_u32(uint32_t *ptr, uint32_t *expectedCurrentValue, uint32_t desiredValue);
211+
212+
/**
213+
* Atomic increment.
214+
* @param valuePtr Target memory location being incremented.
215+
* @param delta The amount being incremented.
216+
* @return The new incremented value.
217+
*/
218+
uint8_t core_util_atomic_incr_u8(uint8_t * valuePtr, uint8_t delta);
219+
220+
/**
221+
* Atomic increment.
222+
* @param valuePtr Target memory location being incremented.
223+
* @param delta The amount being incremented.
224+
* @return The new incremented value.
225+
*/
226+
uint16_t core_util_atomic_incr_u16(uint16_t * valuePtr, uint16_t delta);
227+
228+
/**
229+
* Atomic increment.
230+
* @param valuePtr Target memory location being incremented.
231+
* @param delta The amount being incremented.
232+
* @return The new incremented value.
233+
*/
234+
uint32_t core_util_atomic_incr_u32(uint32_t * valuePtr, uint32_t delta);
235+
236+
/**
237+
* Atomic decrement.
238+
* @param valuePtr Target memory location being decremented.
239+
* @param delta The amount being decremented.
240+
* @return The new decremented value.
241+
*/
242+
uint8_t core_util_atomic_decr_u8(uint8_t * valuePtr, uint8_t delta);
243+
244+
/**
245+
* Atomic decrement.
246+
* @param valuePtr Target memory location being decremented.
247+
* @param delta The amount being decremented.
248+
* @return The new decremented value.
249+
*/
250+
uint16_t core_util_atomic_decr_u16(uint16_t * valuePtr, uint16_t delta);
251+
252+
/**
253+
* Atomic decrement.
254+
* @param valuePtr Target memory location being decremented.
255+
* @param delta The amount being decremented.
256+
* @return The new decremented value.
257+
*/
258+
uint32_t core_util_atomic_decr_u32(uint32_t * valuePtr, uint32_t delta);
259+
51260
#ifdef __cplusplus
52261
} // extern "C"
53262
#endif

0 commit comments

Comments
 (0)