0001 // 0002 // ReadWriteLock.swift 0003 // ReadWriteLock 0004 // 0005 // Created by John Gallagher on 7/17/14. 0006 // Copyright © 2014-2015 Big Nerd Ranch. Licensed under MIT. 0007 // 0008 0009 import Dispatch 0010 #if SWIFT_PACKAGE 0011 import AtomicSwift 0012 #endif 0013 0014 /// A type that mutually excludes execution of code such that only one unit of 0015 /// code is running at any given time. An implementing type may choose to have 0016 /// readers-writer semantics, such that many readers can read at once, or lock 0017 /// around all reads and writes the same way. 0018 public protocol ReadWriteLock{ 0019 /// Call `body` with a reading lock. 0020 /// 0021 /// If the implementing type models a readers-writer lock, this function may 0022 /// behave differently to `withWriteLock(_:)`. 0023 /// 0024 /// - parameter body: A function that reads a value while locked. 0025 /// - returns: The value returned from the given function. 0026 func withReadLock
LockProtected.swift:13 private var lock: ReadWriteLockLockProtected.swift:23 public init(item: T, lock: ReadWriteLock) {ReadWriteLock.swift:38 extension ReadWriteLock {ReadWriteLock.swift:53 public struct DispatchLock: ReadWriteLock {ReadWriteLock.swift:75 public final class SpinLock: ReadWriteLock {ReadWriteLock.swift:103 public final class CASSpinLock: ReadWriteLock {ReadWriteLock.swift:197 public final class PThreadReadWriteLock: ReadWriteLock {<Return>(@noescape body: () throws -> Return) rethrows -> Return 0027 0028 /// Call `body` with a writing lock. 0029 /// 0030 /// If the implementing type models a readers-writer lock, this function may 0031 /// behave differently to `withReadLock(_:)`. 0032 /// 0033 /// - parameter body: A function that writes a value while locked, then returns some value. 0034 /// - returns: The value returned from the given function. 0035 func withWriteLock
LockProtected.swift:32 return try lock.withReadLock {ReadWriteLock.swift:44 return try withReadLock(body)<Return>(@noescape body: () throws -> Return) rethrows -> Return 0036 } 0037 0038 extension ReadWriteLock { 0039 /// Call `body` with a lock. 0040 /// 0041 /// - parameter body: A function that writes a value while locked, then returns some value. 0042 /// - returns: The value returned from the given function. 0043 public func withWriteLock<Return>(@noescape body: () throws -> Return) rethrows -> Return { 0044 return try withReadLock(body) 0045 } 0046 } 0047 0048 /// A locking construct using a counting semaphore from Grand Central Dispatch. 0049 /// This locking type behaves the same for both read and write locks. 0050 /// 0051 /// The semaphore lock performs comparably to a spinlock under little lock 0052 /// contention, and comparably to a platform lock under contention. 0053 public struct DispatchLock: ReadWriteLock { 0054 private let semaphore
LockProtected.swift:41 return try lock.withWriteLock {= dispatch_semaphore_create(1) 0055 0056 /// Create a normal instance. 0057 public init() {} 0058 0059 /// Call `body` with a lock. 0060 /// - parameter body: A function that reads a value while locked. 0061 /// - returns: The value returned from the given function. 0062 public func withReadLock<Return>(@noescape body: () throws -> Return) rethrows -> Return { 0063 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) 0064 defer { 0065 dispatch_semaphore_signal(semaphore) 0066 } 0067 return try body() 0068 } 0069 } 0070 0071 /// A spin lock provided by Darwin, the low-level system under iOS and OS X. 0072 /// 0073 /// A spin lock polls to check the state of the lock, which is much faster 0074 /// when there isn't contention but rapidly slows down otherwise. 0075 public final class SpinLock: ReadWriteLock { 0076 private var lock
ReadWriteLock.swift:63 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)ReadWriteLock.swift:65 dispatch_semaphore_signal(semaphore): UnsafeMutablePointer<OSSpinLock> 0077 0078 /// Allocate a normal spinlock. 0079 public init() { 0080 lock = UnsafeMutablePointer.alloc(1) 0081 lock.initialize(OS_SPINLOCK_INIT) 0082 } 0083 0084 deinit { 0085 lock.destroy() 0086 lock.dealloc(1) 0087 } 0088 0089 /// Call `body` with a lock. 0090 /// - parameter body: A function that reads a value while locked. 0091 /// - returns: The value returned from the given function. 0092 public func withReadLock<Return>(@noescape body: () throws -> Return) rethrows -> Return { 0093 OSSpinLockLock(lock) 0094 defer { 0095 OSSpinLockUnlock(lock) 0096 } 0097 return try body() 0098 } 0099 } 0100 0101 /// A custom spin-lock with readers-writer semantics. The spin lock will poll 0102 /// to check the state of the lock, allowing many readers at the same time. 0103 public final class CASSpinLock
ReadWriteLock.swift:80 lock = UnsafeMutablePointer.alloc(1)ReadWriteLock.swift:81 lock.initialize(OS_SPINLOCK_INIT)ReadWriteLock.swift:85 lock.destroy()ReadWriteLock.swift:86 lock.dealloc(1)ReadWriteLock.swift:93 OSSpinLockLock(lock)ReadWriteLock.swift:95 OSSpinLockUnlock(lock): ReadWriteLock { 0104 // Original inspiration: http://joeduffyblog.com/2009/01/29/a-singleword-readerwriter-spin-lock/ 0105 // Updated/optimized version: https://jfdube.wordpress.com/2014/01/12/optimizing-the-recursive-read-write-spinlock/ 0106 private enum Constants
LockProtected.swift:18 self.init(item: item, lock: CASSpinLock()){ 0107 static var WriterMask
ReadWriteLock.swift:135 while (state.memory & Constants.WriterMask) != 0 {ReadWriteLock.swift:140 if (OSAtomicAdd32Barrier(Constants.WriterOffset, state) & Constants.WriterMask) == Constants.WriterOffset {ReadWriteLock.swift:140 if (OSAtomicAdd32Barrier(Constants.WriterOffset, state) & Constants.WriterMask) == Constants.WriterOffset {ReadWriteLock.swift:140 if (OSAtomicAdd32Barrier(Constants.WriterOffset, state) & Constants.WriterMask) == Constants.WriterOffset {ReadWriteLock.swift:142 while (state.memory & Constants.ReaderMask) != 0 {ReadWriteLock.swift:151 OSAtomicAdd32Barrier(-Constants.WriterOffset, state)ReadWriteLock.swift:156 OSAtomicAdd32Barrier(-Constants.WriterOffset, state)ReadWriteLock.swift:172 while (state.memory & Constants.WriterMask) != 0 {ReadWriteLock.swift:177 if (OSAtomicIncrement32Barrier(state) & Constants.WriterMask) == 0 {: Int32 { return Int32(bitPattern: 0xFFF00000) } 0108 static var ReaderMask
ReadWriteLock.swift:135 while (state.memory & Constants.WriterMask) != 0 {ReadWriteLock.swift:140 if (OSAtomicAdd32Barrier(Constants.WriterOffset, state) & Constants.WriterMask) == Constants.WriterOffset {ReadWriteLock.swift:172 while (state.memory & Constants.WriterMask) != 0 {ReadWriteLock.swift:177 if (OSAtomicIncrement32Barrier(state) & Constants.WriterMask) == 0 {: Int32 { return Int32(bitPattern: 0x000FFFFF) } 0109 static var WriterOffset
ReadWriteLock.swift:142 while (state.memory & Constants.ReaderMask) != 0 {: Int32 { return Int32(bitPattern: 0x00100000) } 0110 } 0111 0112 private var state
ReadWriteLock.swift:140 if (OSAtomicAdd32Barrier(Constants.WriterOffset, state) & Constants.WriterMask) == Constants.WriterOffset {ReadWriteLock.swift:140 if (OSAtomicAdd32Barrier(Constants.WriterOffset, state) & Constants.WriterMask) == Constants.WriterOffset {ReadWriteLock.swift:151 OSAtomicAdd32Barrier(-Constants.WriterOffset, state)ReadWriteLock.swift:156 OSAtomicAdd32Barrier(-Constants.WriterOffset, state): UnsafeMutablePointer<Int32> 0113 0114 /// Allocate the spinlock. 0115 public init
ReadWriteLock.swift:116 state = UnsafeMutablePointer.alloc(1)ReadWriteLock.swift:117 state.initialize(0)ReadWriteLock.swift:121 state.destroy()ReadWriteLock.swift:122 state.dealloc(1)ReadWriteLock.swift:135 while (state.memory & Constants.WriterMask) != 0 {ReadWriteLock.swift:140 if (OSAtomicAdd32Barrier(Constants.WriterOffset, state) & Constants.WriterMask) == Constants.WriterOffset {ReadWriteLock.swift:142 while (state.memory & Constants.ReaderMask) != 0 {ReadWriteLock.swift:151 OSAtomicAdd32Barrier(-Constants.WriterOffset, state)ReadWriteLock.swift:156 OSAtomicAdd32Barrier(-Constants.WriterOffset, state)ReadWriteLock.swift:172 while (state.memory & Constants.WriterMask) != 0 {ReadWriteLock.swift:177 if (OSAtomicIncrement32Barrier(state) & Constants.WriterMask) == 0 {ReadWriteLock.swift:183 OSAtomicDecrement32Barrier(state)ReadWriteLock.swift:188 OSAtomicDecrement32Barrier(state)() { 0116 state = UnsafeMutablePointer.alloc(1) 0117 state.initialize(0) 0118 } 0119 0120 deinit { 0121 state.destroy() 0122 state.dealloc(1) 0123 } 0124 0125 /// Call `body` with a writing lock. 0126 /// 0127 /// The given function is guaranteed to be called exclusively. 0128 /// 0129 /// - parameter body: A function that writes a value while locked, then returns some value. 0130 /// - returns: The value returned from the given function. 0131 public func withWriteLock<Return>(@noescape body: () throws -> Return) rethrows -> Return { 0132 // spin until we acquire write lock 0133 repeat { 0134 // wait for any active writer to release the lock 0135 while (state.memory & Constants.WriterMask) != 0 { 0136 _OSAtomicSpin() 0137 } 0138 0139 // increment the writer count 0140 if (OSAtomicAdd32Barrier(Constants.WriterOffset, state) & Constants.WriterMask) == Constants.WriterOffset { 0141 // wait until there are no more readers 0142 while (state.memory & Constants.ReaderMask) != 0 { 0143 _OSAtomicSpin() 0144 } 0145 0146 // write lock acquired 0147 break 0148 } 0149 0150 // there's another writer active; try again 0151 OSAtomicAdd32Barrier(-Constants.WriterOffset, state) 0152 } while true 0153 0154 defer { 0155 // decrement writers, potentially unblock readers 0156 OSAtomicAdd32Barrier(-Constants.WriterOffset, state) 0157 } 0158 0159 return try body() 0160 } 0161 0162 /// Call `body` with a reading lock. 0163 /// 0164 /// The given function may be called concurrently with reads on other threads. 0165 /// 0166 /// - parameter body: A function that reads a value while locked. 0167 /// - returns: The value returned from the given function. 0168 public func withReadLock<Return>(@noescape body: () throws -> Return) rethrows -> Return { 0169 // spin until we acquire read lock 0170 repeat { 0171 // wait for active writer to release the lock 0172 while (state.memory & Constants.WriterMask) != 0 { 0173 _OSAtomicSpin() 0174 } 0175 0176 // increment the reader count 0177 if (OSAtomicIncrement32Barrier(state) & Constants.WriterMask) == 0 { 0178 // read lock required 0179 break 0180 } 0181 0182 // a writer became active while locking; try again 0183 OSAtomicDecrement32Barrier(state) 0184 } while true 0185 0186 defer { 0187 // decrement readers, potentially unblock writers 0188 OSAtomicDecrement32Barrier(state) 0189 } 0190 0191 return try body() 0192 } 0193 } 0194 0195 /// A readers-writer lock provided by the platform implementation of the 0196 /// POSIX Threads standard. Read more: https://en.wikipedia.org/wiki/POSIX_Threads 0197 public final class PThreadReadWriteLock: ReadWriteLock { 0198 private var lock
LockProtected.swift:18 self.init(item: item, lock: CASSpinLock()): UnsafeMutablePointer<pthread_rwlock_t> 0199 0200 /// Create the standard platform lock. 0201 public init() { 0202 lock = UnsafeMutablePointer.alloc(1) 0203 let status = pthread_rwlock_init(lock, nil) 0204 assert(status == 0) 0205 } 0206 0207 deinit { 0208 let status = pthread_rwlock_destroy(lock) 0209 assert(status == 0) 0210 lock.destroy() 0211 lock.dealloc(1) 0212 } 0213 0214 /// Call `body` with a reading lock. 0215 /// 0216 /// The given function may be called concurrently with reads on other threads. 0217 /// 0218 /// - parameter body: A function that reads a value while locked. 0219 /// - returns: The value returned from the given function. 0220 public func withReadLock<Return>(@noescape body: () throws -> Return) rethrows -> Return { 0221 pthread_rwlock_rdlock(lock) 0222 defer { 0223 pthread_rwlock_unlock(lock) 0224 } 0225 return try body() 0226 } 0227 0228 /// Call `body` with a writing lock. 0229 /// 0230 /// The given function is guaranteed to be called exclusively. 0231 /// 0232 /// - parameter body: A function that writes a value while locked, then returns some value. 0233 /// - returns: The value returned from the given function. 0234 public func withWriteLock<Return>(@noescape body: () throws -> Return) rethrows -> Return { 0235 pthread_rwlock_wrlock(lock) 0236 defer { 0237 pthread_rwlock_unlock(lock) 0238 } 0239 return try body() 0240 } 0241 0242 } 0243
ReadWriteLock.swift:202 lock = UnsafeMutablePointer.alloc(1)ReadWriteLock.swift:203 let status = pthread_rwlock_init(lock, nil)ReadWriteLock.swift:208 let status = pthread_rwlock_destroy(lock)ReadWriteLock.swift:210 lock.destroy()ReadWriteLock.swift:211 lock.dealloc(1)ReadWriteLock.swift:221 pthread_rwlock_rdlock(lock)ReadWriteLock.swift:223 pthread_rwlock_unlock(lock)ReadWriteLock.swift:235 pthread_rwlock_wrlock(lock)ReadWriteLock.swift:237 pthread_rwlock_unlock(lock)