@@ -104,33 +104,97 @@ internal struct UnsafeAtomicState<State: RawRepresentable> where State.RawValue
104104#endif
105105}
106106
107- final class PosixThreadMutex : NSLocking {
108- private var mutex = pthread_mutex_t ( )
107+ /// `Lock` exposes `os_unfair_lock` on supported platforms, with pthread mutex as the
108+ // fallback.
109+ internal class Lock {
110+ #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
111+ @available ( iOS 10 . 0 , * )
112+ @available ( macOS 10 . 12 , * )
113+ @available ( tvOS 10 . 0 , * )
114+ @available ( watchOS 3 . 0 , * )
115+ internal final class UnfairLock : Lock {
116+ private var _lock : os_unfair_lock
117+
118+ override init ( ) {
119+ _lock = os_unfair_lock ( )
120+ super. init ( )
121+ }
109122
110- init ( ) {
111- let result = pthread_mutex_init ( & mutex, nil )
112- precondition ( result == 0 , " Failed to initialize mutex with error \( result) . " )
113- }
123+ override func lock( ) {
124+ withUnsafeMutablePointer ( to: & _lock, os_unfair_lock_lock)
125+ }
114126
115- deinit {
116- let result = pthread_mutex_destroy ( & mutex)
117- precondition ( result == 0 , " Failed to destroy mutex with error \( result) . " )
127+ override func unlock( ) {
128+ withUnsafeMutablePointer ( to: & _lock, os_unfair_lock_unlock)
129+ }
130+
131+ override func `try`( ) -> Bool {
132+ return withUnsafeMutablePointer ( to: & _lock, os_unfair_lock_trylock)
133+ }
118134 }
135+ #endif
136+
137+ internal final class PthreadLock : Lock {
138+ private var _lock : pthread_mutex_t
139+
140+ override init ( ) {
141+ _lock = pthread_mutex_t ( )
142+
143+ let status = withUnsafeMutablePointer ( to: & _lock) { pthread_mutex_init ( $0, nil ) }
144+ assert ( status == 0 , " Unexpected pthread mutex error code: \( status) " )
145+
146+ super. init ( )
147+ }
148+
149+ override func lock( ) {
150+ let status = withUnsafeMutablePointer ( to: & _lock, pthread_mutex_lock)
151+ assert ( status == 0 , " Unexpected pthread mutex error code: \( status) " )
152+ }
153+
154+ override func unlock( ) {
155+ let status = withUnsafeMutablePointer ( to: & _lock, pthread_mutex_unlock)
156+ assert ( status == 0 , " Unexpected pthread mutex error code: \( status) " )
157+ }
158+
159+ override func `try`( ) -> Bool {
160+ let status = withUnsafeMutablePointer ( to: & _lock, pthread_mutex_trylock)
161+ switch status {
162+ case 0 :
163+ return true
164+ case EBUSY:
165+ return false
166+ default :
167+ assertionFailure ( " Unexpected pthread mutex error code: \( status) " )
168+ return false
169+ }
170+ }
119171
120- func lock( ) {
121- let result = pthread_mutex_lock ( & mutex)
122- precondition ( result == 0 , " Failed to lock \( self ) with error \( result) . " )
172+ deinit {
173+ let status = withUnsafeMutablePointer ( to: & _lock, pthread_mutex_destroy)
174+ assert ( status == 0 , " Unexpected pthread mutex error code: \( status) " )
175+ }
123176 }
124177
125- func unlock( ) {
126- let result = pthread_mutex_unlock ( & mutex)
127- precondition ( result == 0 , " Failed to unlock \( self ) with error \( result) . " )
178+ static func make( ) -> Lock {
179+ #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
180+ if #available( * , iOS 10 . 0 , macOS 10 . 12 , tvOS 10 . 0 , watchOS 3 . 0 ) {
181+ return UnfairLock ( )
182+ }
183+ #endif
184+
185+ return PthreadLock ( )
128186 }
187+
188+ private init ( ) { }
189+
190+ func lock( ) { fatalError ( ) }
191+ func unlock( ) { fatalError ( ) }
192+ func `try`( ) -> Bool { fatalError ( ) }
129193}
130194
131195/// An atomic variable.
132196public final class Atomic < Value> {
133- private let lock : PosixThreadMutex
197+ private let lock : Lock
134198 private var _value : Value
135199
136200 /// Atomically get or set the value of the variable.
@@ -150,7 +214,7 @@ public final class Atomic<Value> {
150214 /// - value: Initial value for `self`.
151215 public init ( _ value: Value ) {
152216 _value = value
153- lock = PosixThreadMutex ( )
217+ lock = Lock . make ( )
154218 }
155219
156220 /// Atomically modifies the variable.
0 commit comments