Skip to content

Commit f928b3d

Browse files
committed
Merge pull request #9 from ypopovych/master
Run Loop fixes
2 parents 45bf186 + 93b779d commit f928b3d

File tree

4 files changed

+45
-42
lines changed

4 files changed

+45
-42
lines changed

ExecutionContext/LoopSemaphore.swift

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===--- Semaphore.swift ------------------------------------------------------===//
1+
//===--- LoopSemaphore.swift -----------------------------------------------===//
22
//Copyright (c) 2016 Daniel Leping (dileping)
33
//
44
//Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,41 +16,43 @@
1616

1717
import Foundation
1818

19-
import Dispatch
19+
#if !os(Linux)
20+
import Dispatch
2021

21-
public class DispatchLoopSemaphore : SemaphoreType {
22-
let sema:dispatch_semaphore_t
22+
public class DispatchLoopSemaphore : SemaphoreType {
23+
let sema:dispatch_semaphore_t
2324

24-
public required convenience init() {
25-
self.init(value: 0)
26-
}
25+
public required convenience init() {
26+
self.init(value: 0)
27+
}
2728

28-
public required init(value: Int) {
29-
self.sema = dispatch_semaphore_create(value)
30-
}
29+
public required init(value: Int) {
30+
self.sema = dispatch_semaphore_create(value)
31+
}
3132

32-
public func wait() -> Bool {
33-
return dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER) == 0
34-
}
33+
public func wait() -> Bool {
34+
return dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER) == 0
35+
}
3536

36-
public func wait(until:NSDate?) -> Bool {
37-
let timeout = until?.timeIntervalSinceNow
38-
return wait(timeout)
39-
}
37+
public func wait(until:NSDate?) -> Bool {
38+
let timeout = until?.timeIntervalSinceNow
39+
return wait(timeout)
40+
}
4041

41-
public func wait(timeout: Double?) -> Bool {
42-
guard let timeout = timeout else {
43-
return wait()
42+
public func wait(timeout: Double?) -> Bool {
43+
guard let timeout = timeout else {
44+
return wait()
45+
}
46+
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeout * NSTimeInterval(NSEC_PER_SEC)))
47+
let result = dispatch_semaphore_wait(sema, time)
48+
return result == 0
4449
}
45-
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeout * NSTimeInterval(NSEC_PER_SEC)))
46-
let result = dispatch_semaphore_wait(sema, time)
47-
return result == 0
48-
}
4950

50-
public func signal() -> Int {
51-
return dispatch_semaphore_signal(sema)
51+
public func signal() -> Int {
52+
return dispatch_semaphore_signal(sema)
53+
}
5254
}
53-
}
55+
#endif
5456

5557
extension Optional {
5658
func getOrElse(@autoclosure f:()->Wrapped) -> Wrapped {
@@ -105,7 +107,7 @@ public class CFRunLoopSemaphore : SemaphoreType {
105107
while value <= 0 {
106108
while !self.signaled && !timedout {
107109
RunLoop.runUntilOnce(RunLoop.defaultMode, until: until)
108-
timedout = !until.isGreaterThan(NSDate())
110+
timedout = until.timeIntervalSinceNow <= 0
109111
}
110112
if timedout {
111113
break
@@ -126,4 +128,4 @@ public class CFRunLoopSemaphore : SemaphoreType {
126128
}
127129
}
128130

129-
public typealias LoopSemaphore = CFRunLoopSemaphore
131+
public typealias LoopSemaphore = CFRunLoopSemaphore

ExecutionContext/PThreadExecutionContext.swift

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,23 +94,28 @@
9494
return try syncThroughAsync(task)
9595
}
9696
}
97+
98+
// This class is workaround around retain cycle in pthread run loop creation. See below in init(). Stupid ARC :(
99+
private class RunLoopHolder {
100+
var loop: RunLoop? = nil
101+
}
97102

98103
private class SerialContext : ExecutionContextBase, ExecutionContextType {
99104
private let rl:RunLoop
100105

101106
override init() {
102-
var runLoop:AnyObject?
107+
let holder = RunLoopHolder()
103108
let sema = Semaphore()
104109

105-
PThread(task: {
106-
runLoop = RunLoop.currentCFRunLoop()
110+
PThread(task: { [unowned holder] in
111+
holder.loop = RunLoop.currentRunLoop()
107112
sema.signal()
108113
RunLoop.run()
109114
}).start()
110115

111116
sema.wait()
112117

113-
self.rl = RunLoop(runLoop!)
118+
self.rl = holder.loop!
114119
}
115120

116121
init(runLoop:RunLoop) {

ExecutionContext/RunLoop.swift

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,9 @@ import CoreFoundation
148148
func signal() {
149149
if _source != nil {
150150
CFRunLoopSourceSignal(_source)
151-
for loop in info.runLoops {
152-
loop.wakeUp()
153-
}
151+
}
152+
for loop in info.runLoops {
153+
loop.wakeUp()
154154
}
155155
}
156156
}
@@ -265,10 +265,6 @@ import CoreFoundation
265265
static func mainRunLoop() -> RunLoop {
266266
return MainRunLoop
267267
}
268-
269-
static func currentCFRunLoop() -> AnyObject {
270-
return CFRunLoopGetCurrent()
271-
}
272268

273269
func isCurrent() -> Bool {
274270
return cfRunLoop === CFRunLoopGetCurrent()
@@ -322,7 +318,7 @@ import CoreFoundation
322318
}
323319
wakeUp()
324320
}
325-
}
321+
}
326322

327323
func addDelay(rld: RunLoopDelay, mode: NSString) {
328324
let crld = unsafeBitCast(rld.cfObject, CFRunLoopTimer.self)

Tests/ExecutionContext/ExecutionContextTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class ExecutionContextTests: XCTestCase {
3232
expectation.fulfill()
3333
}
3434

35-
self.waitForExpectationsWithTimeout(1, handler: nil)
35+
self.waitForExpectationsWithTimeout(0, handler: nil)
3636
}
3737

3838
func asyncTest(context:ExecutionContextType) {

0 commit comments

Comments
 (0)