Atomic.swift 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. //
  2. // Atomic.swift
  3. // ReactiveSwift
  4. //
  5. // Created by Justin Spahr-Summers on 2014-06-10.
  6. // Copyright (c) 2014 GitHub. All rights reserved.
  7. //
  8. import Foundation
  9. #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
  10. import MachO
  11. #endif
  12. /// Represents a finite state machine that can transit from one state to
  13. /// another.
  14. internal protocol AtomicStateProtocol {
  15. associatedtype State: RawRepresentable
  16. /// Try to transit from the expected current state to the specified next
  17. /// state.
  18. ///
  19. /// - parameters:
  20. /// - expected: The expected state.
  21. ///
  22. /// - returns:
  23. /// `true` if the transition succeeds. `false` otherwise.
  24. func tryTransiting(from expected: State, to next: State) -> Bool
  25. }
  26. /// A simple, generic lock-free finite state machine.
  27. ///
  28. /// - warning: `deinitialize` must be called to dispose of the consumed memory.
  29. internal struct UnsafeAtomicState<State: RawRepresentable>: AtomicStateProtocol where State.RawValue == Int32 {
  30. internal typealias Transition = (expected: State, next: State)
  31. #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
  32. private let value: UnsafeMutablePointer<Int32>
  33. /// Create a finite state machine with the specified initial state.
  34. ///
  35. /// - parameters:
  36. /// - initial: The desired initial state.
  37. internal init(_ initial: State) {
  38. value = UnsafeMutablePointer<Int32>.allocate(capacity: 1)
  39. value.initialize(to: initial.rawValue)
  40. }
  41. /// Deinitialize the finite state machine.
  42. internal func deinitialize() {
  43. value.deinitialize()
  44. value.deallocate(capacity: 1)
  45. }
  46. /// Compare the current state with the specified state.
  47. ///
  48. /// - parameters:
  49. /// - expected: The expected state.
  50. ///
  51. /// - returns:
  52. /// `true` if the current state matches the expected state. `false`
  53. /// otherwise.
  54. @inline(__always)
  55. internal func `is`(_ expected: State) -> Bool {
  56. return OSAtomicCompareAndSwap32Barrier(expected.rawValue,
  57. expected.rawValue,
  58. value)
  59. }
  60. /// Try to transit from the expected current state to the specified next
  61. /// state.
  62. ///
  63. /// - parameters:
  64. /// - expected: The expected state.
  65. ///
  66. /// - returns:
  67. /// `true` if the transition succeeds. `false` otherwise.
  68. @inline(__always)
  69. internal func tryTransiting(from expected: State, to next: State) -> Bool {
  70. return OSAtomicCompareAndSwap32Barrier(expected.rawValue,
  71. next.rawValue,
  72. value)
  73. }
  74. #else
  75. private let value: Atomic<Int32>
  76. /// Create a finite state machine with the specified initial state.
  77. ///
  78. /// - parameters:
  79. /// - initial: The desired initial state.
  80. internal init(_ initial: State) {
  81. value = Atomic(initial.rawValue)
  82. }
  83. /// Deinitialize the finite state machine.
  84. internal func deinitialize() {}
  85. /// Compare the current state with the specified state.
  86. ///
  87. /// - parameters:
  88. /// - expected: The expected state.
  89. ///
  90. /// - returns:
  91. /// `true` if the current state matches the expected state. `false`
  92. /// otherwise.
  93. internal func `is`(_ expected: State) -> Bool {
  94. return value.modify { $0 == expected.rawValue }
  95. }
  96. /// Try to transit from the expected current state to the specified next
  97. /// state.
  98. ///
  99. /// - parameters:
  100. /// - expected: The expected state.
  101. ///
  102. /// - returns:
  103. /// `true` if the transition succeeds. `false` otherwise.
  104. internal func tryTransiting(from expected: State, to next: State) -> Bool {
  105. return value.modify { value in
  106. if value == expected.rawValue {
  107. value = next.rawValue
  108. return true
  109. }
  110. return false
  111. }
  112. }
  113. #endif
  114. }
  115. final class PosixThreadMutex: NSLocking {
  116. private var mutex = pthread_mutex_t()
  117. init() {
  118. let result = pthread_mutex_init(&mutex, nil)
  119. precondition(result == 0, "Failed to initialize mutex with error \(result).")
  120. }
  121. deinit {
  122. let result = pthread_mutex_destroy(&mutex)
  123. precondition(result == 0, "Failed to destroy mutex with error \(result).")
  124. }
  125. func lock() {
  126. let result = pthread_mutex_lock(&mutex)
  127. precondition(result == 0, "Failed to lock \(self) with error \(result).")
  128. }
  129. func unlock() {
  130. let result = pthread_mutex_unlock(&mutex)
  131. precondition(result == 0, "Failed to unlock \(self) with error \(result).")
  132. }
  133. }
  134. /// An atomic variable.
  135. public final class Atomic<Value>: AtomicProtocol {
  136. private let lock: PosixThreadMutex
  137. private var _value: Value
  138. /// Initialize the variable with the given initial value.
  139. ///
  140. /// - parameters:
  141. /// - value: Initial value for `self`.
  142. public init(_ value: Value) {
  143. _value = value
  144. lock = PosixThreadMutex()
  145. }
  146. /// Atomically modifies the variable.
  147. ///
  148. /// - parameters:
  149. /// - action: A closure that takes the current value.
  150. ///
  151. /// - returns: The result of the action.
  152. @discardableResult
  153. public func modify<Result>(_ action: (inout Value) throws -> Result) rethrows -> Result {
  154. lock.lock()
  155. defer { lock.unlock() }
  156. return try action(&_value)
  157. }
  158. /// Atomically perform an arbitrary action using the current value of the
  159. /// variable.
  160. ///
  161. /// - parameters:
  162. /// - action: A closure that takes the current value.
  163. ///
  164. /// - returns: The result of the action.
  165. @discardableResult
  166. public func withValue<Result>(_ action: (Value) throws -> Result) rethrows -> Result {
  167. lock.lock()
  168. defer { lock.unlock() }
  169. return try action(_value)
  170. }
  171. }
  172. /// An atomic variable which uses a recursive lock.
  173. internal final class RecursiveAtomic<Value>: AtomicProtocol {
  174. private let lock: NSRecursiveLock
  175. private var _value: Value
  176. private let didSetObserver: ((Value) -> Void)?
  177. /// Initialize the variable with the given initial value.
  178. ///
  179. /// - parameters:
  180. /// - value: Initial value for `self`.
  181. /// - name: An optional name used to create the recursive lock.
  182. /// - action: An optional closure which would be invoked every time the
  183. /// value of `self` is mutated.
  184. internal init(_ value: Value, name: StaticString? = nil, didSet action: ((Value) -> Void)? = nil) {
  185. _value = value
  186. lock = NSRecursiveLock()
  187. lock.name = name.map(String.init(describing:))
  188. didSetObserver = action
  189. }
  190. /// Atomically modifies the variable.
  191. ///
  192. /// - parameters:
  193. /// - action: A closure that takes the current value.
  194. ///
  195. /// - returns: The result of the action.
  196. @discardableResult
  197. func modify<Result>(_ action: (inout Value) throws -> Result) rethrows -> Result {
  198. lock.lock()
  199. defer {
  200. didSetObserver?(_value)
  201. lock.unlock()
  202. }
  203. return try action(&_value)
  204. }
  205. /// Atomically perform an arbitrary action using the current value of the
  206. /// variable.
  207. ///
  208. /// - parameters:
  209. /// - action: A closure that takes the current value.
  210. ///
  211. /// - returns: The result of the action.
  212. @discardableResult
  213. func withValue<Result>(_ action: (Value) throws -> Result) rethrows -> Result {
  214. lock.lock()
  215. defer { lock.unlock() }
  216. return try action(_value)
  217. }
  218. }
  219. /// A protocol used to constraint convenience `Atomic` methods and properties.
  220. public protocol AtomicProtocol: class {
  221. associatedtype Value
  222. @discardableResult
  223. func withValue<Result>(_ action: (Value) throws -> Result) rethrows -> Result
  224. @discardableResult
  225. func modify<Result>(_ action: (inout Value) throws -> Result) rethrows -> Result
  226. }
  227. extension AtomicProtocol {
  228. /// Atomically get or set the value of the variable.
  229. public var value: Value {
  230. get {
  231. return withValue { $0 }
  232. }
  233. set(newValue) {
  234. swap(newValue)
  235. }
  236. }
  237. /// Atomically replace the contents of the variable.
  238. ///
  239. /// - parameters:
  240. /// - newValue: A new value for the variable.
  241. ///
  242. /// - returns: The old value.
  243. @discardableResult
  244. public func swap(_ newValue: Value) -> Value {
  245. return modify { (value: inout Value) in
  246. let oldValue = value
  247. value = newValue
  248. return oldValue
  249. }
  250. }
  251. }