@@ -30,12 +30,12 @@ internal class _StateMachine<Progress, Value, Error>
3030
3131 /// wrapper closure for `_initClosure` to invoke only once when started `.Running`,
3232 /// and will be set to `nil` afterward
33- internal var initResumeClosure : ( Void -> Void ) ?
33+ internal var initResumeClosure : _Atomic < ( Void -> Void ) ? > = _Atomic ( nil )
3434
3535 private lazy var _progressTupleHandlers = _Handlers < ProgressTupleHandler > ( )
3636 private lazy var _completionHandlers = _Handlers < Void -> Void > ( )
3737
38- private let _recursiveLock = _RecursiveLock ( )
38+ private var _lock = _RecursiveLock ( )
3939
4040 internal init ( weakified: Bool , paused: Bool )
4141 {
@@ -45,63 +45,63 @@ internal class _StateMachine<Progress, Value, Error>
4545
4646 internal func addProgressTupleHandler( inout token: _HandlerToken ? , _ progressTupleHandler: ProgressTupleHandler ) -> Bool
4747 {
48- self . _recursiveLock . lock ( )
48+ self . _lock . lock ( )
4949 if self . state. rawValue == . Running || self . state. rawValue == . Paused {
5050 token = self . _progressTupleHandlers. append ( progressTupleHandler)
51- self . _recursiveLock . unlock ( )
51+ self . _lock . unlock ( )
5252 return token != nil
5353 }
5454 else {
55- self . _recursiveLock . unlock ( )
55+ self . _lock . unlock ( )
5656 return false
5757 }
5858 }
5959
6060 internal func removeProgressTupleHandler( handlerToken: _HandlerToken ? ) -> Bool
6161 {
62- self . _recursiveLock . lock ( )
62+ self . _lock . lock ( )
6363 if let handlerToken = handlerToken {
6464 let removedHandler = self . _progressTupleHandlers. remove ( handlerToken)
65- self . _recursiveLock . unlock ( )
65+ self . _lock . unlock ( )
6666 return removedHandler != nil
6767 }
6868 else {
69- self . _recursiveLock . unlock ( )
69+ self . _lock . unlock ( )
7070 return false
7171 }
7272 }
7373
7474 internal func addCompletionHandler( inout token: _HandlerToken ? , _ completionHandler: Void -> Void ) -> Bool
7575 {
76- self . _recursiveLock . lock ( )
76+ self . _lock . lock ( )
7777 if self . state. rawValue == . Running || self . state. rawValue == . Paused {
7878 token = self . _completionHandlers. append ( completionHandler)
79- self . _recursiveLock . unlock ( )
79+ self . _lock . unlock ( )
8080 return token != nil
8181 }
8282 else {
83- self . _recursiveLock . unlock ( )
83+ self . _lock . unlock ( )
8484 return false
8585 }
8686 }
8787
8888 internal func removeCompletionHandler( handlerToken: _HandlerToken ? ) -> Bool
8989 {
90- self . _recursiveLock . lock ( )
90+ self . _lock . lock ( )
9191 if let handlerToken = handlerToken {
9292 let removedHandler = self . _completionHandlers. remove ( handlerToken)
93- self . _recursiveLock . unlock ( )
93+ self . _lock . unlock ( )
9494 return removedHandler != nil
9595 }
9696 else {
97- self . _recursiveLock . unlock ( )
97+ self . _lock . unlock ( )
9898 return false
9999 }
100100 }
101101
102102 internal func handleProgress( progress: Progress )
103103 {
104- self . _recursiveLock . lock ( )
104+ self . _lock . lock ( )
105105 if self . state. rawValue == . Running {
106106
107107 let oldProgress = self . progress. rawValue
@@ -114,110 +114,93 @@ internal class _StateMachine<Progress, Value, Error>
114114 for handler in self . _progressTupleHandlers {
115115 handler ( oldProgress: oldProgress, newProgress: progress)
116116 }
117- self . _recursiveLock . unlock ( )
117+ self . _lock . unlock ( )
118118 }
119119 else {
120- self . _recursiveLock . unlock ( )
120+ self . _lock . unlock ( )
121121 }
122122 }
123123
124124 internal func handleFulfill( value: Value )
125125 {
126- self . _recursiveLock . lock ( )
127- if self . state. rawValue == . Running {
128- self . state . rawValue = . Fulfilled
126+ self . _lock . lock ( )
127+ let ( _ , updated ) = self . state. tryUpdate { $0 == . Running ? ( . Fulfilled , true ) : ( $0 , false ) }
128+ if updated {
129129 self . value. rawValue = value
130130 self . _finish ( )
131- self . _recursiveLock . unlock ( )
131+ self . _lock . unlock ( )
132132 }
133133 else {
134- self . _recursiveLock . unlock ( )
134+ self . _lock . unlock ( )
135135 }
136136 }
137137
138138 internal func handleRejectInfo( errorInfo: ErrorInfo )
139139 {
140- self . _recursiveLock. lock ( )
141- if self . state. rawValue == . Running || self . state. rawValue == . Paused {
142- self . state. rawValue = errorInfo. isCancelled ? . Cancelled : . Rejected
140+ self . _lock. lock ( )
141+ let toState = errorInfo. isCancelled ? TaskState . Cancelled : . Rejected
142+ let ( _, updated) = self . state. tryUpdate { $0 == . Running || $0 == . Paused ? ( toState, true ) : ( $0, false ) }
143+ if updated {
143144 self . errorInfo. rawValue = errorInfo
144145 self . _finish ( )
145- self . _recursiveLock . unlock ( )
146+ self . _lock . unlock ( )
146147 }
147148 else {
148- self . _recursiveLock . unlock ( )
149+ self . _lock . unlock ( )
149150 }
150151 }
151152
152153 internal func handlePause( ) -> Bool
153154 {
154- self . _recursiveLock. lock ( )
155- if self . state. rawValue == . Running {
155+ self . _lock. lock ( )
156+ let ( _, updated) = self . state. tryUpdate { $0 == . Running ? ( . Paused, true ) : ( $0, false ) }
157+ if updated {
156158 self . configuration. pause ? ( )
157- self . state. rawValue = . Paused
158- self . _recursiveLock. unlock ( )
159+ self . _lock. unlock ( )
159160 return true
160161 }
161162 else {
162- self . _recursiveLock . unlock ( )
163+ self . _lock . unlock ( )
163164 return false
164165 }
165166 }
166167
167168 internal func handleResume( ) -> Bool
168169 {
169- //
170- // NOTE:
171- // `initResumeClosure` should be invoked first before `configure.resume()`
172- // to let downstream prepare setting upstream's progress/fulfill/reject handlers
173- // before upstream actually starts sending values, which often happens
174- // when downstream's `configure.resume()` is configured to call upstream's `task.resume()`
175- // which eventually calls upstream's `initResumeClosure`
176- // and thus upstream starts sending values.
177- //
178-
179- self . _recursiveLock. lock ( )
180-
181- self . _handleInitResumeIfNeeded ( )
182- let resumed = _handleResume ( )
183-
184- self . _recursiveLock. unlock ( )
185-
186- return resumed
187- }
188-
189- ///
190- /// Invokes `initResumeClosure` on 1st resume (only once).
191- ///
192- /// If initial state is `.Paused`, `state` will be temporarily switched to `.Running`
193- /// during `initResumeClosure` execution, so that Task can call progress/fulfill/reject handlers safely.
194- ///
195- private func _handleInitResumeIfNeeded( )
196- {
197- if ( self . initResumeClosure != nil ) {
170+ self . _lock. lock ( )
171+ if let initResumeClosure = self . initResumeClosure. update ( { _ in nil } ) {
198172
199- let isInitPaused = ( self . state. rawValue == . Paused)
200- if isInitPaused {
201- self . state. rawValue = . Running // switch `.Paused` => `.Resume` temporarily without invoking `configure.resume()`
202- }
173+ self . state. rawValue = . Running
174+ self . _lock. unlock ( )
203175
204- // NOTE: performing `initResumeClosure` might change `state` to `.Fulfilled` or `.Rejected` **immediately**
205- self . initResumeClosure ? ( )
206- self . initResumeClosure = nil
176+ //
177+ // NOTE:
178+ // Don't use `_lock` here so that dispatch_async'ed `handleProgress` inside `initResumeClosure()`
179+ // will be safely called even when current thread goes into sleep.
180+ //
181+ initResumeClosure ( )
207182
208- // switch back to `.Paused` if temporary `.Running` has not changed
209- // so that consecutive `_handleResume()` can perform `configure.resume()`
210- if isInitPaused && self . state. rawValue == . Running {
211- self . state. rawValue = . Paused
212- }
183+ //
184+ // Comment-Out:
185+ // Don't call `configuration.resume()` when lazy starting.
186+ // This prevents inapropriate starting of upstream in ReactKit.
187+ //
188+ //self.configuration.resume?()
189+
190+ return true
191+ }
192+ else {
193+ let resumed = _handleResume ( )
194+ self . _lock. unlock ( )
195+ return resumed
213196 }
214197 }
215198
216199 private func _handleResume( ) -> Bool
217200 {
218- if self . state. rawValue == . Paused {
201+ let ( _, updated) = self . state. tryUpdate { $0 == . Paused ? ( . Running, true ) : ( $0, false ) }
202+ if updated {
219203 self . configuration. resume ? ( )
220- self . state. rawValue = . Running
221204 return true
222205 }
223206 else {
@@ -227,16 +210,16 @@ internal class _StateMachine<Progress, Value, Error>
227210
228211 internal func handleCancel( error: Error ? = nil ) -> Bool
229212 {
230- self . _recursiveLock . lock ( )
231- if self . state. rawValue == . Running || self . state . rawValue == . Paused {
232- self . state . rawValue = . Cancelled
213+ self . _lock . lock ( )
214+ let ( _ , updated ) = self . state. tryUpdate { $0 == . Running || $0 == . Paused ? ( . Cancelled , true ) : ( $0 , false ) }
215+ if updated {
233216 self . errorInfo. rawValue = ErrorInfo ( error: error, isCancelled: true )
234217 self . _finish ( )
235- self . _recursiveLock . unlock ( )
218+ self . _lock . unlock ( )
236219 return true
237220 }
238221 else {
239- self . _recursiveLock . unlock ( )
222+ self . _lock . unlock ( )
240223 return false
241224 }
242225 }
@@ -252,7 +235,7 @@ internal class _StateMachine<Progress, Value, Error>
252235
253236 self . configuration. finish ( )
254237
255- self . initResumeClosure = nil
238+ self . initResumeClosure. rawValue = nil
256239 self . progress. rawValue = nil
257240 }
258241}
0 commit comments