@@ -23,6 +23,54 @@ import CoreFoundation
2323 var cfString : CFString { return unsafeBitCast ( self , CFString . self) }
2424 }
2525
26+ private class TaskQueueElement {
27+ private let task : SafeTask
28+ private let source : RunLoopSource
29+ var next : TaskQueueElement ? = nil
30+
31+ init ( _ task: SafeTask , runLoopSource: RunLoopSource ) {
32+ self . task = task
33+ self . source = runLoopSource
34+ }
35+
36+ func run( ) {
37+ task ( )
38+ }
39+ }
40+
41+ private class TaskQueue {
42+ private let lock = NSLock ( )
43+ private var head : TaskQueueElement ? = nil
44+ private var tail : TaskQueueElement ? = nil
45+
46+ func enqueue( elem: TaskQueueElement ) {
47+ defer {
48+ lock. unlock ( )
49+ }
50+ lock. lock ( )
51+ if tail == nil {
52+ head = elem
53+ tail = elem
54+ } else {
55+ tail!. next = elem
56+ tail = elem
57+ }
58+ }
59+
60+ func dequeue( ) -> TaskQueueElement ? {
61+ defer {
62+ lock. unlock ( )
63+ }
64+ lock. lock ( )
65+ let elem = head
66+ head = head? . next
67+ if head == nil {
68+ tail = nil
69+ }
70+ return elem
71+ }
72+ }
73+
2674 private class RunLoopCallbackInfo {
2775 private var task : SafeTask
2876 private var runLoops : [ RunLoop ] = [ ]
@@ -37,10 +85,19 @@ import CoreFoundation
3785 }
3886
3987 private func runLoopCallbackInfoRun( i: UnsafeMutablePointer < Void > ) {
40- let info = Unmanaged < RunLoopCallbackInfo > . fromOpaque ( COpaquePointer ( i) ) . takeRetainedValue ( )
88+ let info = Unmanaged < RunLoopCallbackInfo > . fromOpaque ( COpaquePointer ( i) ) . takeUnretainedValue ( )
4189 info. run ( )
4290 }
4391
92+ private func runLoopCallbackInfoRetain( i: UnsafePointer < Void > ) -> UnsafePointer < Void > {
93+ Unmanaged < RunLoopCallbackInfo > . fromOpaque ( COpaquePointer ( i) ) . retain ( )
94+ return i
95+ }
96+
97+ private func runLoopCallbackInfoRelease( i: UnsafePointer < Void > ) {
98+ Unmanaged < RunLoopCallbackInfo > . fromOpaque ( COpaquePointer ( i) ) . release ( )
99+ }
100+
44101 private protocol RunLoopCallback {
45102 var info : RunLoopCallbackInfo { get }
46103 var cfObject : AnyObject { get }
@@ -56,9 +113,9 @@ import CoreFoundation
56113 if _source == nil {
57114 var context = CFRunLoopSourceContext (
58115 version: 0 ,
59- info: UnsafeMutablePointer < Void > ( Unmanaged . passRetained ( info) . toOpaque ( ) ) ,
60- retain: nil ,
61- release: nil ,
116+ info: UnsafeMutablePointer < Void > ( Unmanaged . passUnretained ( info) . toOpaque ( ) ) ,
117+ retain: runLoopCallbackInfoRetain ,
118+ release: runLoopCallbackInfoRelease ,
62119 copyDescription: nil ,
63120 equal: nil ,
64121 hash: nil ,
@@ -76,6 +133,19 @@ import CoreFoundation
76133 self . info = RunLoopCallbackInfo ( task)
77134 self . priority = priority
78135 }
136+
137+ deinit {
138+ if _source != nil && CFRunLoopSourceIsValid ( _source) {
139+ CFRunLoopSourceInvalidate ( _source)
140+ _source = nil
141+ }
142+ }
143+
144+ func signal( ) {
145+ if _source != nil {
146+ CFRunLoopSourceSignal ( _source)
147+ }
148+ }
79149 }
80150
81151 private func timerRunCallback( timer: CFRunLoopTimer ! , i: UnsafeMutablePointer < Void > ) {
@@ -92,9 +162,9 @@ import CoreFoundation
92162 if _timer == nil {
93163 var context = CFRunLoopTimerContext (
94164 version: 0 ,
95- info: UnsafeMutablePointer < Void > ( Unmanaged . passRetained ( info) . toOpaque ( ) ) ,
96- retain: nil ,
97- release: nil ,
165+ info: UnsafeMutablePointer < Void > ( Unmanaged . passUnretained ( info) . toOpaque ( ) ) ,
166+ retain: runLoopCallbackInfoRetain ,
167+ release: runLoopCallbackInfoRelease ,
98168 copyDescription: nil
99169 )
100170 _timer = CFRunLoopTimerCreate ( nil , CFAbsoluteTimeGetCurrent ( ) + delay, - 1 , 0 , 0 , timerRunCallback, & context)
@@ -111,35 +181,42 @@ import CoreFoundation
111181
112182 class RunLoop {
113183 private let cfRunLoop : CFRunLoop !
114- private let autoStop : Bool
184+
185+ private var taskQueueSource : RunLoopSource
186+ private var taskQueue : TaskQueue
115187
116188 #if !os(Linux)
117189 static let defaultMode : NSString = " kCFRunLoopDefaultMode " as NSString
118190 #else
119191 static let defaultMode : NSString = " kCFRunLoopDefaultMode " . bridge ( )
120192 #endif
121193
122- init ( _ cfRunLoop: CFRunLoop , autoStop : Bool = true ) {
194+ init ( _ cfRunLoop: CFRunLoop ) {
123195 self . cfRunLoop = cfRunLoop
124- self . autoStop = autoStop
196+
197+ let queue = TaskQueue ( )
198+
199+ taskQueueSource = RunLoopSource ( {
200+ var elem = queue. dequeue ( )
201+ while elem != nil {
202+ elem!. run ( )
203+ elem = queue. dequeue ( )
204+ }
205+ } )
206+ taskQueue = queue
207+ addSource ( taskQueueSource, mode: RunLoop . defaultMode, retainLoop: false )
125208 }
126209
127- convenience init ( _ runLoop: AnyObject , autoStop : Bool = true ) {
128- self . init ( unsafeBitCast ( runLoop, CFRunLoop . self) , autoStop : autoStop )
210+ convenience init ( _ runLoop: AnyObject ) {
211+ self . init ( unsafeBitCast ( runLoop, CFRunLoop . self) )
129212 }
130213
131- deinit {
132- if autoStop && cfRunLoop != nil {
133- CFRunLoopStop ( cfRunLoop)
134- }
135- }
136-
137- static func currentRunLoop( autoStop: Bool = false ) -> RunLoop {
138- return RunLoop ( CFRunLoopGetCurrent ( ) , autoStop: autoStop)
214+ static func currentRunLoop( ) -> RunLoop {
215+ return RunLoop ( CFRunLoopGetCurrent ( ) )
139216 }
140217
141218 static func mainRunLoop( ) -> RunLoop {
142- return RunLoop ( CFRunLoopGetMain ( ) , autoStop : false )
219+ return RunLoop ( CFRunLoopGetMain ( ) )
143220 }
144221
145222 static func currentCFRunLoop( ) -> AnyObject {
@@ -156,33 +233,45 @@ import CoreFoundation
156233
157234 static func runInMode( mode: NSString ) {
158235 #if !os(Linux)
159- while CFRunLoopRunInMode ( mode. cfString, Double . infinity, false ) != . Stopped { }
236+ var result : CFRunLoopRunResult
237+ repeat {
238+ result = CFRunLoopRunInMode ( mode. cfString, Double . infinity, false )
239+ } while result != . Finished && result != . Stopped
160240 #else
161- while CFRunLoopRunInMode ( mode. cfString, Double . infinity, false ) != Int32 ( kCFRunLoopRunStopped) { }
241+ var result : Int32
242+ repeat {
243+ result = CFRunLoopRunInMode ( mode. cfString, Double . infinity, false )
244+ } while result != Int32 ( kCFRunLoopRunStopped) && result != Int32 ( kCFRunLoopRunFinished)
162245 #endif
163246 }
164247
165248 @noreturn static func runForever( ) {
166249 while true { run ( ) }
167250 }
168251
169- func addSource( rls: RunLoopSource , mode: NSString ) {
252+ func addSource( rls: RunLoopSource , mode: NSString , retainLoop : Bool = true ) {
170253 let crls = unsafeBitCast ( rls. cfObject, CFRunLoopSource . self)
171254 if CFRunLoopSourceIsValid ( crls) {
172255 CFRunLoopAddSource ( cfRunLoop, crls, mode. cfString)
173- rls. info. runLoops. append ( self )
174- CFRunLoopSourceSignal ( crls )
256+ if retainLoop { rls. info. runLoops. append ( self ) }
257+ rls . signal ( )
175258 CFRunLoopWakeUp ( cfRunLoop)
176259 }
177260 }
178261
179262 func addDelay( rld: RunLoopDelay , mode: NSString ) {
180263 let crld = unsafeBitCast ( rld. cfObject, CFRunLoopTimer . self)
181- if CFRunLoopTimerIsValid ( crld) {
264+ if CFRunLoopTimerIsValid ( crld) && ( rld . info . runLoops . count == 0 || rld . info . runLoops [ 0 ] === self ) {
182265 CFRunLoopAddTimer ( cfRunLoop, crld, mode. cfString)
183266 rld. info. runLoops. append ( self )
184267 CFRunLoopWakeUp ( cfRunLoop)
185268 }
186269 }
270+
271+ func addTask( task: SafeTask ) {
272+ taskQueue. enqueue ( TaskQueueElement ( task, runLoopSource: taskQueueSource) )
273+ taskQueueSource. signal ( )
274+ CFRunLoopWakeUp ( cfRunLoop)
275+ }
187276 }
188277//#endif
0 commit comments