Skip to content

Commit b2328b5

Browse files
committed
[NFC] Move protocol AtomicStorage into its own source file
1 parent addac7b commit b2328b5

File tree

2 files changed

+282
-271
lines changed

2 files changed

+282
-271
lines changed
Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift Atomics open source project
4+
//
5+
// Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
/// The storage representation for an atomic value, providing pointer-based
14+
/// atomic operations. This is a low-level implementation detail of atomic
15+
/// types; instead of directly handling conforming types, it is usually better
16+
/// to use the `UnsafeAtomic` or `ManagedAtomic` generics -- these provide more
17+
/// convenient and safer interfaces while also ensuring that the storage is
18+
/// correctly constructed and destroyed.
19+
///
20+
/// Logically, atomic storage representations are neither value- nor reference
21+
/// types: they should be treated as non-copiable values with a custom
22+
/// destructor. Such constructs cannot currently be modeled directly in Swift,
23+
/// so types conforming to this protocol must be handled carefully to prevent
24+
/// accidental copying. For example, it usually isn't safe to pass around atomic
25+
/// storage representations as function arguments or return values. Instead,
26+
/// they are usually addressed through unsafe pointers.
27+
public protocol AtomicStorage {
28+
/// The type whose values this storage representation is representing.
29+
associatedtype Value
30+
31+
/// Encode the supplied value into its atomic storage representation.
32+
///
33+
/// Note: This is not an atomic operation. This call may have side effects
34+
/// (such as unpaired retains of strong references) that will need to be
35+
/// undone by calling `dispose()` before the storage value is deinitialized.
36+
init(_ value: __owned Value)
37+
38+
/// Prepare this atomic storage value for deinitialization, extracting the
39+
/// logical value it represents. This invalidates this atomic storage; you
40+
/// must not perform any operations on it after this call (except for
41+
/// deinitialization).
42+
///
43+
/// This call prevents resource leaks when destroying the storage
44+
/// representation of certain `AtomicValue` types. (In particular, ones that
45+
/// model strong references.)
46+
///
47+
/// Note: This is not an atomic operation. Logically, it implements a custom
48+
/// destructor for the underlying non-copiable value.
49+
__consuming func dispose() -> Value
50+
51+
/// Atomically loads and returns the value referenced by the given pointer,
52+
/// applying the specified memory ordering.
53+
///
54+
/// - Parameter pointer: A memory location previously initialized with a value
55+
/// returned by `prepareAtomicRepresentation(for:)`.
56+
/// - Parameter ordering: The memory ordering to apply on this operation.
57+
/// - Returns: The current value referenced by `pointer`.
58+
@_semantics("atomics.requires_constant_orderings")
59+
static func atomicLoad(
60+
at pointer: UnsafeMutablePointer<Self>,
61+
ordering: AtomicLoadOrdering
62+
) -> Value
63+
64+
/// Atomically sets the value referenced by `pointer` to `desired`,
65+
/// applying the specified memory ordering.
66+
///
67+
/// - Parameter desired: The desired new value.
68+
/// - Parameter pointer: A memory location previously initialized with a value
69+
/// returned by `prepareAtomicRepresentation(for:)`.
70+
/// - Parameter ordering: The memory ordering to apply on this operation.
71+
@_semantics("atomics.requires_constant_orderings")
72+
static func atomicStore(
73+
_ desired: __owned Value,
74+
at pointer: UnsafeMutablePointer<Self>,
75+
ordering: AtomicStoreOrdering
76+
)
77+
78+
/// Atomically sets the value referenced by `pointer` to `desired` and returns
79+
/// the original value, applying the specified memory ordering.
80+
///
81+
/// - Parameter desired: The desired new value.
82+
/// - Parameter pointer: A memory location previously initialized with a value
83+
/// returned by `prepareAtomicRepresentation(for:)`.
84+
/// - Parameter ordering: The memory ordering to apply on this operation.
85+
/// - Returns: The original value.
86+
@_semantics("atomics.requires_constant_orderings")
87+
static func atomicExchange(
88+
_ desired: __owned Value,
89+
at pointer: UnsafeMutablePointer<Self>,
90+
ordering: AtomicUpdateOrdering
91+
) -> Value
92+
93+
/// Perform an atomic compare and exchange operation on the value referenced
94+
/// by `pointer`, applying the specified memory ordering.
95+
///
96+
/// This operation performs the following algorithm as a single atomic
97+
/// transaction:
98+
///
99+
/// ```
100+
/// atomic(self) { currentValue in
101+
/// let original = currentValue
102+
/// guard original == expected else { return (false, original) }
103+
/// currentValue = desired
104+
/// return (true, original)
105+
/// }
106+
/// ```
107+
///
108+
/// This method implements a "strong" compare and exchange operation
109+
/// that does not permit spurious failures.
110+
///
111+
/// - Parameter expected: The expected current value.
112+
/// - Parameter desired: The desired new value.
113+
/// - Parameter pointer: A memory location previously initialized with a value
114+
/// returned by `prepareAtomicRepresentation(for:)`.
115+
/// - Parameter ordering: The memory ordering to apply on this operation.
116+
/// - Returns: A tuple `(exchanged, original)`, where `exchanged` is true if
117+
/// the exchange was successful, and `original` is the original value.
118+
@_semantics("atomics.requires_constant_orderings")
119+
static func atomicCompareExchange(
120+
expected: Value,
121+
desired: __owned Value,
122+
at pointer: UnsafeMutablePointer<Self>,
123+
ordering: AtomicUpdateOrdering
124+
) -> (exchanged: Bool, original: Value)
125+
126+
/// Perform an atomic compare and exchange operation on the value referenced
127+
/// by `pointer`, applying the specified success/failure memory orderings.
128+
///
129+
/// This operation performs the following algorithm as a single atomic
130+
/// transaction:
131+
///
132+
/// ```
133+
/// atomic(self) { currentValue in
134+
/// let original = currentValue
135+
/// guard original == expected else { return (false, original) }
136+
/// currentValue = desired
137+
/// return (true, original)
138+
/// }
139+
/// ```
140+
///
141+
/// The `successOrdering` argument specifies the memory ordering to use when
142+
/// the operation manages to update the current value, while `failureOrdering`
143+
/// will be used when the operation leaves the value intact.
144+
///
145+
/// This method implements a "strong" compare and exchange operation
146+
/// that does not permit spurious failures.
147+
///
148+
/// - Parameter expected: The expected current value.
149+
/// - Parameter desired: The desired new value.
150+
/// - Parameter pointer: A memory location previously initialized with a value
151+
/// returned by `prepareSelf(for:)`.
152+
/// - Parameter successOrdering: The memory ordering to apply if this
153+
/// operation performs the exchange.
154+
/// - Parameter failureOrdering: The memory ordering to apply on this
155+
/// operation does not perform the exchange.
156+
/// - Returns: A tuple `(exchanged, original)`, where `exchanged` is true if
157+
/// the exchange was successful, and `original` is the original value.
158+
@_semantics("atomics.requires_constant_orderings")
159+
static func atomicCompareExchange(
160+
expected: Value,
161+
desired: __owned Value,
162+
at pointer: UnsafeMutablePointer<Self>,
163+
successOrdering: AtomicUpdateOrdering,
164+
failureOrdering: AtomicLoadOrdering
165+
) -> (exchanged: Bool, original: Value)
166+
167+
/// Perform an atomic weak compare and exchange operation on the value
168+
/// referenced by `pointer`, applying the specified memory orderings.
169+
/// This compare-exchange variant is allowed to spuriously fail; it
170+
/// is designed to be called in a loop until it indicates a successful
171+
/// exchange has happened.
172+
///
173+
/// This operation performs the following algorithm as a single atomic
174+
/// transaction:
175+
///
176+
/// ```
177+
/// atomic(self) { currentValue in
178+
/// let original = currentValue
179+
/// guard original == expected else { return (false, original) }
180+
/// currentValue = desired
181+
/// return (true, original)
182+
/// }
183+
/// ```
184+
///
185+
/// (In this weak form, transient conditions may cause the `original ==
186+
/// expected` check to sometimes return false when the two values are in fact
187+
/// the same.)
188+
///
189+
/// - Parameter expected: The expected current value.
190+
/// - Parameter desired: The desired new value.
191+
/// - Parameter pointer: A memory location previously initialized with a value
192+
/// returned by `prepareAtomicRepresentation(for:)`.
193+
/// - Parameter ordering: The memory ordering to apply on this operation.
194+
/// - Returns: A tuple `(exchanged, original)`, where `exchanged` is true if
195+
/// the exchange was successful, and `original` is the original value.
196+
@_semantics("atomics.requires_constant_orderings")
197+
static func atomicWeakCompareExchange(
198+
expected: Value,
199+
desired: __owned Value,
200+
at pointer: UnsafeMutablePointer<Self>,
201+
ordering: AtomicUpdateOrdering
202+
) -> (exchanged: Bool, original: Value)
203+
204+
/// Perform an atomic weak compare and exchange operation on the value
205+
/// referenced by `pointer`, applying the specified success/failure memory
206+
/// orderings. This compare-exchange variant is allowed to spuriously fail; it
207+
/// is designed to be called in a loop until it indicates a successful
208+
/// exchange has happened.
209+
///
210+
/// This operation performs the following algorithm as a single atomic
211+
/// transaction:
212+
///
213+
/// ```
214+
/// atomic(self) { currentValue in
215+
/// let original = currentValue
216+
/// guard original == expected else { return (false, original) }
217+
/// currentValue = desired
218+
/// return (true, original)
219+
/// }
220+
/// ```
221+
///
222+
/// (In this weak form, transient conditions may cause the `original ==
223+
/// expected` check to sometimes return false when the two values are in fact
224+
/// the same.)
225+
///
226+
/// The `successOrdering` argument specifies the memory ordering to use when the
227+
/// operation manages to update the current value, while `failureOrdering`
228+
/// will be used when the operation leaves the value intact.
229+
///
230+
/// - Parameter expected: The expected current value.
231+
/// - Parameter desired: The desired new value.
232+
/// - Parameter pointer: A memory location previously initialized with a value
233+
/// returned by `prepareAtomicRepresentation(for:)`.
234+
/// - Parameter successOrdering: The memory ordering to apply if this
235+
/// operation performs the exchange.
236+
/// - Parameter failureOrdering: The memory ordering to apply on this
237+
/// operation does not perform the exchange.
238+
/// - Returns: A tuple `(exchanged, original)`, where `exchanged` is true if
239+
/// the exchange was successful, and `original` is the original value.
240+
@_semantics("atomics.requires_constant_orderings")
241+
static func atomicWeakCompareExchange(
242+
expected: Value,
243+
desired: __owned Value,
244+
at pointer: UnsafeMutablePointer<Self>,
245+
successOrdering: AtomicUpdateOrdering,
246+
failureOrdering: AtomicLoadOrdering
247+
) -> (exchanged: Bool, original: Value)
248+
}
249+
250+
extension AtomicStorage {
251+
@_semantics("atomics.requires_constant_orderings")
252+
@_transparent @_alwaysEmitIntoClient
253+
public static func atomicCompareExchange(
254+
expected: Value,
255+
desired: __owned Value,
256+
at pointer: UnsafeMutablePointer<Self>,
257+
ordering: AtomicUpdateOrdering
258+
) -> (exchanged: Bool, original: Value) {
259+
atomicCompareExchange(
260+
expected: expected,
261+
desired: desired,
262+
at: pointer,
263+
successOrdering: ordering,
264+
failureOrdering: ._failureOrdering(for: ordering))
265+
}
266+
267+
@_semantics("atomics.requires_constant_orderings")
268+
@_transparent @_alwaysEmitIntoClient
269+
public static func atomicWeakCompareExchange(
270+
expected: Value,
271+
desired: __owned Value,
272+
at pointer: UnsafeMutablePointer<Self>,
273+
ordering: AtomicUpdateOrdering
274+
) -> (exchanged: Bool, original: Value) {
275+
atomicWeakCompareExchange(
276+
expected: expected,
277+
desired: desired,
278+
at: pointer,
279+
successOrdering: ordering,
280+
failureOrdering: ._failureOrdering(for: ordering))
281+
}
282+
}

0 commit comments

Comments
 (0)