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
LockProtected.swift:13
    private var lock: ReadWriteLock
LockProtected.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 {
{ 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:32
        return try lock.withReadLock {
ReadWriteLock.swift:44
        return try withReadLock(body)
<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:41
        return try lock.withWriteLock {
<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
ReadWriteLock.swift:63
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
ReadWriteLock.swift:65
            dispatch_semaphore_signal(semaphore)
= 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: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)
: 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
LockProtected.swift:18
        self.init(item: item, lock: CASSpinLock())
: 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
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 {
{ 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: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:142
                while (state.memory & Constants.ReaderMask) != 0 {
: Int32 { return Int32(bitPattern: 0x000FFFFF) } 0109 static var 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:151
            OSAtomicAdd32Barrier(-Constants.WriterOffset, state)
ReadWriteLock.swift:156
            OSAtomicAdd32Barrier(-Constants.WriterOffset, state)
: Int32 { return Int32(bitPattern: 0x00100000) } 0110 } 0111 0112 private var state
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)
: UnsafeMutablePointer<Int32> 0113 0114 /// Allocate the spinlock. 0115 public init
LockProtected.swift:18
        self.init(item: item, lock: CASSpinLock())
() { 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
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)
: 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