@@ -196,23 +196,31 @@ fileprivate func refcountPointer(for object: UnsafeMutablePointer<HeapObject>) -
196196 return UnsafeMutablePointer < Int > ( UnsafeRawPointer ( object) . advanced ( by: MemoryLayout< Int> . size) . _rawValue)
197197}
198198
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) )
201201}
202202
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) )
205205}
206206
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) )
209209 return oldValue - n
210210}
211211
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)
214214}
215215
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+ }
216224
217225
218226/// Exclusivity checking
@@ -233,11 +241,24 @@ public func swift_endAccess(buffer: UnsafeMutableRawPointer) {
233241
234242@_silgen_name ( " swift_once " )
235243public 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 {
239254 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
241262 }
242263}
243264
0 commit comments