@@ -196,23 +196,31 @@ fileprivate func refcountPointer(for object: UnsafeMutablePointer<HeapObject>) -
196
196
return UnsafeMutablePointer < Int > ( UnsafeRawPointer ( object) . advanced ( by: MemoryLayout< Int> . size) . _rawValue)
197
197
}
198
198
199
- fileprivate func loadRelaxed( _ refcount : UnsafeMutablePointer < Int > ) -> Int {
200
- Int ( Builtin . atomicload_monotonic_Word ( refcount . _rawValue) )
199
+ fileprivate func loadRelaxed( _ atomic : UnsafeMutablePointer < Int > ) -> Int {
200
+ Int ( Builtin . atomicload_monotonic_Word ( atomic . _rawValue) )
201
201
}
202
202
203
- fileprivate func loadAcquire( _ refcount : UnsafeMutablePointer < Int > ) -> Int {
204
- Int ( Builtin . atomicload_acquire_Word ( refcount . _rawValue) )
203
+ fileprivate func loadAcquire( _ atomic : UnsafeMutablePointer < Int > ) -> Int {
204
+ Int ( Builtin . atomicload_acquire_Word ( atomic . _rawValue) )
205
205
}
206
206
207
- fileprivate func subFetchAcquireRelease( _ refcount : UnsafeMutablePointer < Int > , n: Int ) -> Int {
208
- let oldValue = Int ( Builtin . atomicrmw_sub_acqrel_Word ( refcount . _rawValue, n. _builtinWordValue) )
207
+ fileprivate func subFetchAcquireRelease( _ atomic : UnsafeMutablePointer < Int > , n: Int ) -> Int {
208
+ let oldValue = Int ( Builtin . atomicrmw_sub_acqrel_Word ( atomic . _rawValue, n. _builtinWordValue) )
209
209
return oldValue - n
210
210
}
211
211
212
- fileprivate func addRelaxed( _ refcount : UnsafeMutablePointer < Int > , n: Int ) {
213
- _ = Builtin . atomicrmw_add_monotonic_Word ( refcount . _rawValue, n. _builtinWordValue)
212
+ fileprivate func addRelaxed( _ atomic : UnsafeMutablePointer < Int > , n: Int ) {
213
+ _ = Builtin . atomicrmw_add_monotonic_Word ( atomic . _rawValue, n. _builtinWordValue)
214
214
}
215
215
216
+ fileprivate func compareExchangeRelaxed( _ atomic: UnsafeMutablePointer < Int > , expectedOldValue: Int , desiredNewValue: Int ) -> Bool {
217
+ let ( _, won) = Builtin . cmpxchg_monotonic_monotonic_Word ( atomic. _rawValue, expectedOldValue. _builtinWordValue, desiredNewValue. _builtinWordValue)
218
+ return Bool ( won)
219
+ }
220
+
221
+ fileprivate func storeRelease( _ atomic: UnsafeMutablePointer < Int > , newValue: Int ) {
222
+ Builtin . atomicstore_release_Word ( atomic. _rawValue, newValue. _builtinWordValue)
223
+ }
216
224
217
225
218
226
/// Exclusivity checking
@@ -233,11 +241,24 @@ public func swift_endAccess(buffer: UnsafeMutableRawPointer) {
233
241
234
242
@_silgen_name ( " swift_once " )
235
243
public func swift_once( predicate: UnsafeMutablePointer < Int > , fn: ( @convention ( c) ( UnsafeMutableRawPointer ) -> ( ) ) , context: UnsafeMutableRawPointer ) {
236
- // TODO/FIXME: The following only works in single-threaded environments.
237
- if predicate. pointee == 0 {
238
- predicate. pointee = 1
244
+ let checkedLoadAcquire = { predicate in
245
+ let value = loadAcquire ( predicate)
246
+ assert ( value == - 1 || value == 0 || value == 1 )
247
+ return value
248
+ }
249
+
250
+ if checkedLoadAcquire ( predicate) < 0 { return }
251
+
252
+ let won = compareExchangeRelaxed ( predicate, expectedOldValue: 0 , desiredNewValue: 1 )
253
+ if won {
239
254
fn ( context)
240
- predicate. pointee = - 1
255
+ storeRelease ( predicate, newValue: - 1 )
256
+ return
257
+ }
258
+
259
+ // TODO: This should really use an OS provided lock
260
+ while checkedLoadAcquire ( predicate) >= 0 {
261
+ // spin
241
262
}
242
263
}
243
264
0 commit comments