0001 /* 0002 * Sync (sync.swift) - Please be Safe 0003 * 0004 * Copyright (C) 2015 ONcast, LLC. All Rights Reserved. 0005 * Created by Josh Baker (joshbaker77@gmail.com) 0006 * 0007 * This software may be modified and distributed under the terms 0008 * of the MIT license. See the LICENSE file for details. 0009 * 0010 * Portions of the documentation of this code are reproduced from 0011 * work created and shared by Google and used according to terms 0012 * described in the Creative Commons 3.0 Attribution License. 0013 * 0014 * http://golang.org/pkg/sync/ 0015 */ 0016 0017 #if os(Linux) 0018 import Glibc 0019 #endif 0020 0021 import Foundation 0022 0023 /// The WaitResult enum is used as a return value by Mutex.wait() 0024 public enum WaitResult{ 0025 /// The wait resulted in a signal 0026 case Signaled
sync.swift:109 public func wait(timeout : NSTimeInterval = -1) -> WaitResult {0027 /// The wait resulted in a timeout 0028 case TimedOut
sync.swift:112 return .Signaledsync.swift:124 return .Signaled0029 } 0030 0031 /// A Mutex is a mutual exclusion lock. 0032 public class Mutex
sync.swift:126 return .TimedOut{ 0033 private var mutex
atomic.swift:32 private var mutex = Mutex()chan.swift:13 private let idMutex = Mutex()chan.swift:36 internal let cond = Cond(Mutex())select.swift:74 var cond = Cond(Mutex())select.swift:147 private let selectMutex = Mutex()sync.swift:71 public let mutex : Mutexsync.swift:74 public init(_ mutex : Mutex){sync.swift:132 private var mutex = Mutex()sync.swift:167 private var cond = Cond(Mutex())= pthread_mutex_t() 0034 /// Returns a new Mutex. 0035 public init
sync.swift:36 pthread_mutex_init(&mutex, nil)sync.swift:39 pthread_mutex_destroy(&mutex)sync.swift:43 pthread_mutex_lock(&mutex)sync.swift:52 pthread_mutex_unlock(&mutex)sync.swift:111 pthread_cond_wait(&cond, &mutex.mutex)sync.swift:123 if (pthread_cond_timedwait(&cond, &mutex.mutex, &ts) == 0) {(){ 0036 pthread_mutex_init(&mutex, nil) 0037 } 0038 deinit{ 0039 pthread_mutex_destroy(&mutex) 0040 } 0041 /// Locks the mutex. If the lock is already in use, the calling operation blocks until the mutex is available. 0042 public func lock
atomic.swift:32 private var mutex = Mutex()chan.swift:13 private let idMutex = Mutex()chan.swift:36 internal let cond = Cond(Mutex())select.swift:74 var cond = Cond(Mutex())select.swift:147 private let selectMutex = Mutex()sync.swift:132 private var mutex = Mutex()sync.swift:167 private var cond = Cond(Mutex())(){ 0043 pthread_mutex_lock(&mutex) 0044 } 0045 /** 0046 Unlocks the mutex. It's an undefined error if mutex is not locked on entry to unlock. 0047 0048 A locked Mutex is not associated with a particular operation. 0049 It is allowed for one operation to lock a Mutex and then arrange for another operation to unlock it. 0050 */ 0051 public func unlock
atomic.swift:40 mutex.lock()atomic.swift:46 mutex.lock()atomic.swift:52 atomic.mutex.lock()atomic.swift:54 mutex.lock()atomic.swift:61 mutex.lock()atomic.swift:68 lhs.mutex.lock()atomic.swift:69 if lhs !== rhs { rhs.mutex.lock() }atomic.swift:72 lhs.mutex.lock()chan.swift:44 idMutex.lock()chan.swift:54 cond.mutex.lock()chan.swift:65 cond.mutex.lock()chan.swift:76 cond.mutex.lock()chan.swift:82 cond.mutex.lock()chan.swift:98 cond.mutex.lock()select.swift:35 chan.cond.mutex.lock()select.swift:42 chan.cond.mutex.lock()select.swift:121 cond.mutex.lock()select.swift:182 selectMutex.lock()sync.swift:58 lock()sync.swift:150 mutex.lock()sync.swift:181 cond.mutex.lock()sync.swift:199 cond.mutex.lock()(){ 0052 pthread_mutex_unlock(&mutex) 0053 } 0054 0055 /// Locks the mutex before calling the function. Unlocks after closure is completed 0056 /// - Parameter: closure Closure function 0057 public func lock(closure : ()->()) { 0058 lock() 0059 closure() 0060 unlock() 0061 } 0062 } 0063 0064 /** 0065 `Cond` implements a condition variable, a rendezvous point for an operation waiting for or announcing the occurrence of an event. 0066 0067 Each `Cond` has an associated `Mutex`, which must be held when changing the condition and when calling the `wait` method. 0068 */ 0069 public class Cond
atomic.swift:41 defer { mutex.unlock() }atomic.swift:47 defer { mutex.unlock() }atomic.swift:53 defer { atomic.mutex.unlock() }atomic.swift:55 defer { mutex.unlock() }atomic.swift:62 defer { mutex.unlock() }atomic.swift:75 lhs.mutex.unlock()atomic.swift:76 if lhs !== rhs { rhs.mutex.unlock() }atomic.swift:79 lhs.mutex.unlock()chan.swift:47 idMutex.unlock()chan.swift:55 defer { cond.mutex.unlock() }chan.swift:67 cond.mutex.unlock()chan.swift:77 defer { cond.mutex.unlock() }chan.swift:83 defer { cond.mutex.unlock() }chan.swift:99 defer { cond.mutex.unlock() }select.swift:36 defer { chan.cond.mutex.unlock() }select.swift:43 defer { chan.cond.mutex.unlock() }select.swift:123 cond.mutex.unlock()select.swift:186 selectMutex.unlock()sync.swift:60 unlock()sync.swift:151 defer { mutex.unlock() }sync.swift:182 defer { cond.mutex.unlock() }sync.swift:200 defer { cond.mutex.unlock() }sync.swift:204 cond.mutex.unlock(){ 0070 private var cond
chan.swift:36 internal let cond = Cond(Mutex())chan.swift:39 internal var gconds : [Cond] = []select.swift:18 func register(cond: Cond)select.swift:19 func unregister(cond: Cond)select.swift:33 func register(cond: Cond){select.swift:40 func unregister(cond: Cond){select.swift:74 var cond = Cond(Mutex())sync.swift:167 private var cond = Cond(Mutex())= pthread_cond_t() 0071 public let mutex
sync.swift:76 pthread_cond_init(&cond, nil)sync.swift:79 pthread_cond_destroy(&cond)sync.swift:83 pthread_cond_broadcast(&cond)sync.swift:87 pthread_cond_signal(&cond)sync.swift:111 pthread_cond_wait(&cond, &mutex.mutex)sync.swift:123 if (pthread_cond_timedwait(&cond, &mutex.mutex, &ts) == 0) {: Mutex 0072 /// Returns a new Cond. 0073 /// - Parameter mutex: A Mutex object. 0074 public init
chan.swift:54 cond.mutex.lock()chan.swift:55 defer { cond.mutex.unlock() }chan.swift:65 cond.mutex.lock()chan.swift:67 cond.mutex.unlock()chan.swift:76 cond.mutex.lock()chan.swift:77 defer { cond.mutex.unlock() }chan.swift:82 cond.mutex.lock()chan.swift:83 defer { cond.mutex.unlock() }chan.swift:98 cond.mutex.lock()chan.swift:99 defer { cond.mutex.unlock() }select.swift:35 chan.cond.mutex.lock()select.swift:36 defer { chan.cond.mutex.unlock() }select.swift:42 chan.cond.mutex.lock()select.swift:43 defer { chan.cond.mutex.unlock() }select.swift:121 cond.mutex.lock()select.swift:123 cond.mutex.unlock()sync.swift:75 self.mutex = mutexsync.swift:111 pthread_cond_wait(&cond, &mutex.mutex)sync.swift:123 if (pthread_cond_timedwait(&cond, &mutex.mutex, &ts) == 0) {sync.swift:181 cond.mutex.lock()sync.swift:182 defer { cond.mutex.unlock() }sync.swift:199 cond.mutex.lock()sync.swift:200 defer { cond.mutex.unlock() }sync.swift:204 cond.mutex.unlock()(_ mutex : Mutex){ 0075 self.mutex = mutex 0076 pthread_cond_init(&cond, nil) 0077 } 0078 deinit { 0079 pthread_cond_destroy(&cond) 0080 } 0081 /// Wakes all operations waiting on `Cond`. 0082 public func broadcast
chan.swift:36 internal let cond = Cond(Mutex())select.swift:74 var cond = Cond(Mutex())sync.swift:167 private var cond = Cond(Mutex())() { 0083 pthread_cond_broadcast(&cond) 0084 } 0085 /// Wakes one operations waiting on `Cond`. 0086 public func signal() { 0087 pthread_cond_signal(&cond) 0088 } 0089 /** 0090 0091 Atomically unlocks `.mutex` and suspends execution of the calling operation. 0092 After later resuming execution, `waita locks `.mutex' before returning. 0093 Unlike in other systems, `wait` cannot return unless awoken by `broadcast` or `signal', or the `timeout` param has been reached. 0094 0095 Because `.mutex` is not locked when 'wait first resumes, the caller typically cannot assume that the condition is true when `wait` returns. 0096 Instead, the caller should `wait` in a loop: 0097 0098 ``` 0099 cond.mutex.lock() 0100 while !condition() { 0101 cond.mutex.wait() 0102 } 0103 ... make use of condition ... 0104 cond.mutex.unlock() 0105 ``` 0106 */ 0107 /// - Parameter timeout: The length of time to wait. Default is forever. 0108 /// - Returns: WaitResult 0109 public func wait
chan.swift:63 cond.broadcast()chan.swift:66 cond.broadcast()sync.swift:191 cond.broadcast()(timeout : NSTimeInterval = -1) -> WaitResult { 0110 if timeout < 0 { 0111 pthread_cond_wait(&cond, &mutex.mutex) 0112 return .Signaled 0113 } 0114 let timeInMs = Int(timeout * 1000) 0115 var tv = timeval() 0116 var ts = timespec() 0117 gettimeofday(&tv, nil) 0118 ts.tv_sec = time(nil) + timeInMs / 1000 0119 let intermediate = 1000 * 1000 * (timeInMs % 1000) 0120 ts.tv_nsec = Int(tv.tv_usec * 1000 + intermediate) 0121 ts.tv_sec += ts.tv_nsec / 1000000000 0122 ts.tv_nsec %= 1000000000 0123 if (pthread_cond_timedwait(&cond, &mutex.mutex, &ts) == 0) { 0124 return .Signaled 0125 } 0126 return .TimedOut 0127 } 0128 } 0129 0130 /// Once is an object that will perform exactly one action. 0131 public class Once { 0132 private var mutex
chan.swift:94 cond.wait()chan.swift:112 cond.wait()select.swift:122 cond.wait(0.25)sync.swift:202 cond.wait()= Mutex() 0133 private var oncer
sync.swift:150 mutex.lock()sync.swift:151 defer { mutex.unlock() }= false 0134 /// Returns a new Once. 0135 public init() {} 0136 /** 0137 Calls the `action` if and only if `doit` is being called for the first time for this instance of `Once`. In other words, given 0138 0139 ``` 0140 var once Once 0141 ``` 0142 0143 If `doit` is called multiple times, only the first call will invoke `action`, even if `action` has a different value in each invocation. 0144 A new instance of `Once` is required for each function to execute. 0145 0146 This method is intended for initialization that must be run exactly once. 0147 */ 0148 /// - Parameter action: An action function. 0149 public func doit(action: ()->()) { 0150 mutex.lock() 0151 defer { mutex.unlock() } 0152 if oncer{ 0153 return 0154 } 0155 oncer = true 0156 action() 0157 } 0158 } 0159 0160 /** 0161 A WaitGroup waits for a collection of operations to finish. 0162 The main operation calls 'add' to set the number of operation to wait for. 0163 Then each of the operations runs and calls 'done' when finished. 0164 At the same time, 'wait' can be used to block until all operations have finished. 0165 */ 0166 public class WaitGroup { 0167 private var cond
sync.swift:152 if oncer{sync.swift:155 oncer = true= Cond(Mutex()) 0168 private var count
sync.swift:181 cond.mutex.lock()sync.swift:182 defer { cond.mutex.unlock() }sync.swift:191 cond.broadcast()sync.swift:199 cond.mutex.lock()sync.swift:200 defer { cond.mutex.unlock() }sync.swift:202 cond.wait()sync.swift:204 cond.mutex.unlock()= 0 0169 /// Returns a new WaitGroup. 0170 public init() {} 0171 /** 0172 Adds delta, which may be negative, to the WaitGroup counter. 0173 If the counter becomes Zero, all operations blocked on 'wait' are released. 0174 If the counter goes negative, 'add' fires a system exception. 0175 0176 Note that calls with a positive delta that occur when the counter is Zero must happen before a 'wait'. 0177 Calls with a negative delta, or calls with a positive delta that start when the counter is greater than zero, may happen at any time. 0178 Typically this means the calls to 'add' should execute before the statement creating the operation or other event to be waited for. 0179 */ 0180 public func add
sync.swift:183 count += deltasync.swift:184 if count < 0 {sync.swift:201 while count > 0 {(delta: Int) { 0181 cond.mutex.lock() 0182 defer { cond.mutex.unlock() } 0183 count += delta 0184 if count < 0 { 0185 #if os(Linux) 0186 assertionFailure("negative WaitGroup counter") 0187 #else 0188 NSException.raise("Exception", format: "negative WaitGroup counter", arguments: getVaList([])) 0189 #endif 0190 } 0191 cond.broadcast() 0192 } 0193 /// Decrements the WaitGroup counter. 0194 public func done() { 0195 add(-1) 0196 } 0197 /// Blocks until the WaitGroup counter is Zero. 0198 public func wait() { 0199 cond.mutex.lock() 0200 defer { cond.mutex.unlock() } 0201 while count > 0 { 0202 cond.wait() 0203 } 0204 cond.mutex.unlock() 0205 } 0206 } 0207
sync.swift:195 add(-1)