|
26 | 26 | import Foundation
|
27 | 27 | import CoreFoundation
|
28 | 28 | import Result
|
| 29 | + #if os(Linux) |
| 30 | + import Glibc |
| 31 | + #endif |
29 | 32 |
|
30 | 33 | private func thread_proc(pm: UnsafeMutablePointer<Void>) -> UnsafeMutablePointer<Void> {
|
31 | 34 | let pthread = Unmanaged<PThread>.fromOpaque(COpaquePointer(pm)).takeRetainedValue()
|
|
54 | 57 | pthread_create(thread, nil, thread_proc, UnsafeMutablePointer<Void>(Unmanaged.passRetained(self).toOpaque()))
|
55 | 58 | }
|
56 | 59 | }
|
| 60 | + |
| 61 | + |
| 62 | + private class RunLoopFinalizer { |
| 63 | + private let rl: CFRunLoop! |
| 64 | + init(_ runLoop: CFRunLoop!) { |
| 65 | + self.rl = runLoop |
| 66 | + } |
| 67 | + deinit { |
| 68 | + CFRunLoopStop(rl) |
| 69 | + } |
| 70 | + } |
| 71 | + |
| 72 | + private class RunLoopObject { |
| 73 | + private var cfObject:AnyObject? = nil |
| 74 | + private let task:SafeTask |
| 75 | + private let finalizer:RunLoopFinalizer? |
| 76 | + |
| 77 | + init(_ task:SafeTask, runLoopFinalizer: RunLoopFinalizer?) { |
| 78 | + self.task = task |
| 79 | + self.finalizer = runLoopFinalizer |
| 80 | + } |
| 81 | + |
| 82 | + func addToRunLoop(runLoop:CFRunLoop, mode: CFString) { |
| 83 | + if cfObject == nil { |
| 84 | + self.cfObject = createCFObject() |
| 85 | + } |
| 86 | + addCFObject(runLoop, mode: mode) |
| 87 | + } |
| 88 | + |
| 89 | + func signal() {} |
| 90 | + |
| 91 | + private func createCFObject() -> AnyObject? { return nil } |
| 92 | + |
| 93 | + private func addCFObject(runLoop:CFRunLoop, mode: CFString) {} |
| 94 | + } |
57 | 95 |
|
58 | 96 | private func sourceMain(rls: UnsafeMutablePointer<Void>) {
|
59 |
| - let runLoopSource = Unmanaged<RunLoopSource>.fromOpaque(COpaquePointer(rls)).takeUnretainedValue() |
60 |
| - runLoopSource.cfSource = nil |
| 97 | + let runLoopSource = Unmanaged<RunLoopObject>.fromOpaque(COpaquePointer(rls)).takeUnretainedValue() |
| 98 | + runLoopSource.cfObject = nil |
61 | 99 | runLoopSource.task()
|
62 | 100 | }
|
63 | 101 |
|
64 | 102 | private func sourceCancel(rls: UnsafeMutablePointer<Void>, rL: CFRunLoop!, mode:CFString!) {
|
65 |
| - let runLoopSource = Unmanaged<RunLoopSource>.fromOpaque(COpaquePointer(rls)).takeUnretainedValue() |
66 |
| - runLoopSource.cfSource = nil |
| 103 | + let runLoopSource = Unmanaged<RunLoopObject>.fromOpaque(COpaquePointer(rls)).takeUnretainedValue() |
| 104 | + runLoopSource.cfObject = nil |
67 | 105 | }
|
68 | 106 |
|
69 | 107 | private func sourceRetain(rls: UnsafePointer<Void>) -> UnsafePointer<Void> {
|
70 |
| - Unmanaged<RunLoopSource>.fromOpaque(COpaquePointer(rls)).retain() |
| 108 | + Unmanaged<RunLoopObject>.fromOpaque(COpaquePointer(rls)).retain() |
71 | 109 | return rls
|
72 | 110 | }
|
73 | 111 |
|
74 | 112 | private func sourceRelease(rls: UnsafePointer<Void>) {
|
75 |
| - Unmanaged<RunLoopSource>.fromOpaque(COpaquePointer(rls)).release() |
| 113 | + Unmanaged<RunLoopObject>.fromOpaque(COpaquePointer(rls)).release() |
76 | 114 | }
|
77 | 115 |
|
78 |
| - private class RunLoopSource { |
79 |
| - private var cfSource:CFRunLoopSource? = nil |
80 |
| - private let task:SafeTask |
| 116 | + private class RunLoopSource : RunLoopObject { |
81 | 117 | private let priority:Int
|
82 | 118 |
|
83 |
| - init(_ task: SafeTask, priority: Int = 0) { |
84 |
| - self.task = task |
| 119 | + init(_ task: SafeTask, priority: Int = 0, finalizer: RunLoopFinalizer?) { |
85 | 120 | self.priority = priority
|
| 121 | + super.init(task, runLoopFinalizer: finalizer) |
86 | 122 | }
|
87 | 123 |
|
88 | 124 | deinit {
|
89 |
| - if let s = cfSource { |
| 125 | + if let s = cfObject as! CFRunLoopSource? { |
90 | 126 | if CFRunLoopSourceIsValid(s) { CFRunLoopSourceInvalidate(s) }
|
91 | 127 | }
|
92 | 128 | }
|
93 |
| - |
94 |
| - func addToRunLoop(runLoop:CFRunLoop, mode: CFString) { |
95 |
| - if cfSource == nil { |
96 |
| - var context = CFRunLoopSourceContext( |
97 |
| - version: 0, |
98 |
| - info: UnsafeMutablePointer<Void>(Unmanaged.passUnretained(self).toOpaque()), |
99 |
| - retain: sourceRetain, |
100 |
| - release: sourceRelease, |
101 |
| - copyDescription: nil, |
102 |
| - equal: nil, |
103 |
| - hash: nil, |
104 |
| - schedule: nil, |
105 |
| - cancel: sourceCancel, |
106 |
| - perform: sourceMain |
107 |
| - ) |
108 |
| - self.cfSource = CFRunLoopSourceCreate(nil, priority, &context) |
109 |
| - } |
110 |
| - |
111 |
| - CFRunLoopAddSource(runLoop, cfSource!, mode) |
| 129 | + |
| 130 | + private override func createCFObject() -> AnyObject? { |
| 131 | + var context = CFRunLoopSourceContext( |
| 132 | + version: 0, |
| 133 | + info: UnsafeMutablePointer<Void>(Unmanaged.passUnretained(self).toOpaque()), |
| 134 | + retain: sourceRetain, |
| 135 | + release: sourceRelease, |
| 136 | + copyDescription: nil, |
| 137 | + equal: nil, |
| 138 | + hash: nil, |
| 139 | + schedule: nil, |
| 140 | + cancel: sourceCancel, |
| 141 | + perform: sourceMain |
| 142 | + ) |
| 143 | + return CFRunLoopSourceCreate(nil, priority, &context) |
112 | 144 | }
|
113 |
| - |
114 |
| - func signal() { |
115 |
| - if let s = cfSource { |
| 145 | + |
| 146 | + private override func addCFObject(runLoop:CFRunLoop, mode: CFString) { |
| 147 | + CFRunLoopAddSource(runLoop, (cfObject as! CFRunLoopSource?)!, mode) |
| 148 | + } |
| 149 | + |
| 150 | + override func signal() { |
| 151 | + if let s = cfObject as! CFRunLoopSource? { |
116 | 152 | CFRunLoopSourceSignal(s)
|
117 | 153 | }
|
118 | 154 | }
|
119 | 155 | }
|
120 | 156 |
|
| 157 | + private func timerCallback(timer: CFRunLoopTimer!, rlt: UnsafeMutablePointer<Void>) { |
| 158 | + sourceMain(rlt) |
| 159 | + } |
| 160 | + |
| 161 | + private class RunLoopDelay : RunLoopObject { |
| 162 | + private let delay:CFTimeInterval |
| 163 | + |
| 164 | + init(_ task: SafeTask, delay: CFTimeInterval, finalizer: RunLoopFinalizer?) { |
| 165 | + self.delay = delay |
| 166 | + super.init(task, runLoopFinalizer: finalizer) |
| 167 | + } |
| 168 | + |
| 169 | + deinit { |
| 170 | + if let t = cfObject as! CFRunLoopTimer? { |
| 171 | + if CFRunLoopTimerIsValid(t) { CFRunLoopTimerInvalidate(t) } |
| 172 | + } |
| 173 | + } |
| 174 | + |
| 175 | + private override func createCFObject() -> AnyObject? { |
| 176 | + var context = CFRunLoopTimerContext( |
| 177 | + version: 0, |
| 178 | + info: UnsafeMutablePointer<Void>(Unmanaged.passUnretained(self).toOpaque()), |
| 179 | + retain: sourceRetain, |
| 180 | + release: sourceRelease, |
| 181 | + copyDescription: nil |
| 182 | + ) |
| 183 | + return CFRunLoopTimerCreate(nil, CFAbsoluteTimeGetCurrent()+delay, -1, 0, 0, timerCallback, &context) |
| 184 | + } |
| 185 | + |
| 186 | + private override func addCFObject(runLoop:CFRunLoop, mode: CFString) { |
| 187 | + CFRunLoopAddTimer(runLoop, (cfObject as! CFRunLoopTimer?)!, mode) |
| 188 | + } |
| 189 | + } |
| 190 | + |
121 | 191 | private extension ExecutionContextType {
|
122 | 192 | func syncThroughAsync<ReturnType>(task:() throws -> ReturnType) throws -> ReturnType {
|
123 | 193 | var result:Result<ReturnType, AnyError>?
|
|
143 | 213 | thread.start()
|
144 | 214 | }
|
145 | 215 |
|
| 216 | + func async(after:Double, task:SafeTask) { |
| 217 | + let thread = PThread(task: { |
| 218 | + let sec = time_t(after) |
| 219 | + let nsec = Int((after - Double(sec)) * 1000 * 1000 * 1000)//nano seconds |
| 220 | + var time = timespec(tv_sec:sec, tv_nsec: nsec) |
| 221 | + |
| 222 | + nanosleep(&time, nil) |
| 223 | + task() |
| 224 | + }) |
| 225 | + thread.start() |
| 226 | + } |
| 227 | + |
146 | 228 | func sync<ReturnType>(task:() throws -> ReturnType) throws -> ReturnType {
|
147 | 229 | return try syncThroughAsync(task)
|
148 | 230 | }
|
149 | 231 | }
|
150 | 232 |
|
151 | 233 | private class SerialContext : ExecutionContextBase, ExecutionContextType {
|
152 | 234 | private let rl:CFRunLoop!
|
153 |
| - private let ownRunLoop:Bool |
| 235 | + private let finalizer: RunLoopFinalizer? |
154 | 236 |
|
155 | 237 | #if !os(Linux)
|
156 | 238 | private static let defaultMode:CFString = "kCFRunLoopDefaultMode" as NSString
|
|
159 | 241 | #endif
|
160 | 242 |
|
161 | 243 | override init() {
|
162 |
| - ownRunLoop = true |
163 | 244 | var runLoop:CFRunLoop?
|
164 | 245 | let cond = NSCondition()
|
165 | 246 | cond.lock()
|
|
172 | 253 | cond.wait()
|
173 | 254 | cond.unlock()
|
174 | 255 | self.rl = runLoop!
|
| 256 | + finalizer = RunLoopFinalizer(self.rl) |
175 | 257 | }
|
176 | 258 |
|
177 | 259 | init(runLoop:CFRunLoop!) {
|
178 |
| - ownRunLoop = false |
179 | 260 | rl = runLoop
|
180 |
| - } |
181 |
| - |
182 |
| - deinit { |
183 |
| - if ownRunLoop { |
184 |
| - let runLoop = rl |
185 |
| - performRunLoopSource(RunLoopSource({ |
186 |
| - CFRunLoopStop(runLoop) |
187 |
| - }, |
188 |
| - priority: -32768) |
189 |
| - ) |
190 |
| - } |
| 261 | + finalizer = nil |
191 | 262 | }
|
192 | 263 |
|
193 | 264 | #if !os(Linux)
|
|
200 | 271 | }
|
201 | 272 | #endif
|
202 | 273 |
|
203 |
| - private func performRunLoopSource(rls: RunLoopSource) { |
204 |
| - rls.addToRunLoop(rl, mode: SerialContext.defaultMode) |
205 |
| - rls.signal() |
| 274 | + private func performRunLoopObject(rlo: RunLoopObject) { |
| 275 | + rlo.addToRunLoop(rl, mode: SerialContext.defaultMode) |
| 276 | + rlo.signal() |
| 277 | + CFRunLoopWakeUp(rl) |
206 | 278 | }
|
207 | 279 |
|
208 | 280 | func async(task:SafeTask) {
|
209 |
| - performRunLoopSource(RunLoopSource(task)) |
| 281 | + performRunLoopObject(RunLoopSource(task, finalizer: finalizer)) |
| 282 | + } |
| 283 | + |
| 284 | + func async(after:Double, task:SafeTask) { |
| 285 | + performRunLoopObject(RunLoopDelay(task, delay: after, finalizer: finalizer)) |
210 | 286 | }
|
211 | 287 |
|
212 | 288 | func sync<ReturnType>(task:() throws -> ReturnType) throws -> ReturnType {
|
|
240 | 316 | return try inner.sync(task)
|
241 | 317 | }
|
242 | 318 |
|
| 319 | + public func async(after:Double, task:SafeTask) { |
| 320 | + inner.async(after, task: task) |
| 321 | + } |
| 322 | + |
243 | 323 | public static let main:ExecutionContextType = PThreadExecutionContext(inner: SerialContext(runLoop: CFRunLoopGetMain()))
|
244 | 324 | public static let global:ExecutionContextType = PThreadExecutionContext(kind: .Parallel)
|
245 | 325 | }
|
|
0 commit comments