Skip to content

Commit 577301a

Browse files
committed
Merge pull request #2 from ypopovych/master
Delay implementation for linux
2 parents 401d48c + 1ff5da9 commit 577301a

File tree

1 file changed

+132
-52
lines changed

1 file changed

+132
-52
lines changed

ExecutionContext/PThreadExecutionContext.swift

Lines changed: 132 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
import Foundation
2727
import CoreFoundation
2828
import Result
29+
#if os(Linux)
30+
import Glibc
31+
#endif
2932

3033
private func thread_proc(pm: UnsafeMutablePointer<Void>) -> UnsafeMutablePointer<Void> {
3134
let pthread = Unmanaged<PThread>.fromOpaque(COpaquePointer(pm)).takeRetainedValue()
@@ -54,70 +57,137 @@
5457
pthread_create(thread, nil, thread_proc, UnsafeMutablePointer<Void>(Unmanaged.passRetained(self).toOpaque()))
5558
}
5659
}
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+
}
5795

5896
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
6199
runLoopSource.task()
62100
}
63101

64102
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
67105
}
68106

69107
private func sourceRetain(rls: UnsafePointer<Void>) -> UnsafePointer<Void> {
70-
Unmanaged<RunLoopSource>.fromOpaque(COpaquePointer(rls)).retain()
108+
Unmanaged<RunLoopObject>.fromOpaque(COpaquePointer(rls)).retain()
71109
return rls
72110
}
73111

74112
private func sourceRelease(rls: UnsafePointer<Void>) {
75-
Unmanaged<RunLoopSource>.fromOpaque(COpaquePointer(rls)).release()
113+
Unmanaged<RunLoopObject>.fromOpaque(COpaquePointer(rls)).release()
76114
}
77115

78-
private class RunLoopSource {
79-
private var cfSource:CFRunLoopSource? = nil
80-
private let task:SafeTask
116+
private class RunLoopSource : RunLoopObject {
81117
private let priority:Int
82118

83-
init(_ task: SafeTask, priority: Int = 0) {
84-
self.task = task
119+
init(_ task: SafeTask, priority: Int = 0, finalizer: RunLoopFinalizer?) {
85120
self.priority = priority
121+
super.init(task, runLoopFinalizer: finalizer)
86122
}
87123

88124
deinit {
89-
if let s = cfSource {
125+
if let s = cfObject as! CFRunLoopSource? {
90126
if CFRunLoopSourceIsValid(s) { CFRunLoopSourceInvalidate(s) }
91127
}
92128
}
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)
112144
}
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? {
116152
CFRunLoopSourceSignal(s)
117153
}
118154
}
119155
}
120156

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+
121191
private extension ExecutionContextType {
122192
func syncThroughAsync<ReturnType>(task:() throws -> ReturnType) throws -> ReturnType {
123193
var result:Result<ReturnType, AnyError>?
@@ -143,14 +213,26 @@
143213
thread.start()
144214
}
145215

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+
146228
func sync<ReturnType>(task:() throws -> ReturnType) throws -> ReturnType {
147229
return try syncThroughAsync(task)
148230
}
149231
}
150232

151233
private class SerialContext : ExecutionContextBase, ExecutionContextType {
152234
private let rl:CFRunLoop!
153-
private let ownRunLoop:Bool
235+
private let finalizer: RunLoopFinalizer?
154236

155237
#if !os(Linux)
156238
private static let defaultMode:CFString = "kCFRunLoopDefaultMode" as NSString
@@ -159,7 +241,6 @@
159241
#endif
160242

161243
override init() {
162-
ownRunLoop = true
163244
var runLoop:CFRunLoop?
164245
let cond = NSCondition()
165246
cond.lock()
@@ -172,22 +253,12 @@
172253
cond.wait()
173254
cond.unlock()
174255
self.rl = runLoop!
256+
finalizer = RunLoopFinalizer(self.rl)
175257
}
176258

177259
init(runLoop:CFRunLoop!) {
178-
ownRunLoop = false
179260
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
191262
}
192263

193264
#if !os(Linux)
@@ -200,13 +271,18 @@
200271
}
201272
#endif
202273

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)
206278
}
207279

208280
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))
210286
}
211287

212288
func sync<ReturnType>(task:() throws -> ReturnType) throws -> ReturnType {
@@ -240,6 +316,10 @@
240316
return try inner.sync(task)
241317
}
242318

319+
public func async(after:Double, task:SafeTask) {
320+
inner.async(after, task: task)
321+
}
322+
243323
public static let main:ExecutionContextType = PThreadExecutionContext(inner: SerialContext(runLoop: CFRunLoopGetMain()))
244324
public static let global:ExecutionContextType = PThreadExecutionContext(kind: .Parallel)
245325
}

0 commit comments

Comments
 (0)