|
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