@@ -30,12 +30,12 @@ internal class _StateMachine<Progress, Value, Error>
30
30
31
31
/// wrapper closure for `_initClosure` to invoke only once when started `.Running`,
32
32
/// and will be set to `nil` afterward
33
- internal var initResumeClosure : ( Void -> Void ) ?
33
+ internal var initResumeClosure : _Atomic < ( Void -> Void ) ? > = _Atomic ( nil )
34
34
35
35
private lazy var _progressTupleHandlers = _Handlers < ProgressTupleHandler > ( )
36
36
private lazy var _completionHandlers = _Handlers < Void -> Void > ( )
37
37
38
- private let _recursiveLock = _RecursiveLock ( )
38
+ private var _lock = _RecursiveLock ( )
39
39
40
40
internal init ( weakified: Bool , paused: Bool )
41
41
{
@@ -45,63 +45,63 @@ internal class _StateMachine<Progress, Value, Error>
45
45
46
46
internal func addProgressTupleHandler( inout token: _HandlerToken ? , _ progressTupleHandler: ProgressTupleHandler ) -> Bool
47
47
{
48
- self . _recursiveLock . lock ( )
48
+ self . _lock . lock ( )
49
49
if self . state. rawValue == . Running || self . state. rawValue == . Paused {
50
50
token = self . _progressTupleHandlers. append ( progressTupleHandler)
51
- self . _recursiveLock . unlock ( )
51
+ self . _lock . unlock ( )
52
52
return token != nil
53
53
}
54
54
else {
55
- self . _recursiveLock . unlock ( )
55
+ self . _lock . unlock ( )
56
56
return false
57
57
}
58
58
}
59
59
60
60
internal func removeProgressTupleHandler( handlerToken: _HandlerToken ? ) -> Bool
61
61
{
62
- self . _recursiveLock . lock ( )
62
+ self . _lock . lock ( )
63
63
if let handlerToken = handlerToken {
64
64
let removedHandler = self . _progressTupleHandlers. remove ( handlerToken)
65
- self . _recursiveLock . unlock ( )
65
+ self . _lock . unlock ( )
66
66
return removedHandler != nil
67
67
}
68
68
else {
69
- self . _recursiveLock . unlock ( )
69
+ self . _lock . unlock ( )
70
70
return false
71
71
}
72
72
}
73
73
74
74
internal func addCompletionHandler( inout token: _HandlerToken ? , _ completionHandler: Void -> Void ) -> Bool
75
75
{
76
- self . _recursiveLock . lock ( )
76
+ self . _lock . lock ( )
77
77
if self . state. rawValue == . Running || self . state. rawValue == . Paused {
78
78
token = self . _completionHandlers. append ( completionHandler)
79
- self . _recursiveLock . unlock ( )
79
+ self . _lock . unlock ( )
80
80
return token != nil
81
81
}
82
82
else {
83
- self . _recursiveLock . unlock ( )
83
+ self . _lock . unlock ( )
84
84
return false
85
85
}
86
86
}
87
87
88
88
internal func removeCompletionHandler( handlerToken: _HandlerToken ? ) -> Bool
89
89
{
90
- self . _recursiveLock . lock ( )
90
+ self . _lock . lock ( )
91
91
if let handlerToken = handlerToken {
92
92
let removedHandler = self . _completionHandlers. remove ( handlerToken)
93
- self . _recursiveLock . unlock ( )
93
+ self . _lock . unlock ( )
94
94
return removedHandler != nil
95
95
}
96
96
else {
97
- self . _recursiveLock . unlock ( )
97
+ self . _lock . unlock ( )
98
98
return false
99
99
}
100
100
}
101
101
102
102
internal func handleProgress( progress: Progress )
103
103
{
104
- self . _recursiveLock . lock ( )
104
+ self . _lock . lock ( )
105
105
if self . state. rawValue == . Running {
106
106
107
107
let oldProgress = self . progress. rawValue
@@ -114,110 +114,93 @@ internal class _StateMachine<Progress, Value, Error>
114
114
for handler in self . _progressTupleHandlers {
115
115
handler ( oldProgress: oldProgress, newProgress: progress)
116
116
}
117
- self . _recursiveLock . unlock ( )
117
+ self . _lock . unlock ( )
118
118
}
119
119
else {
120
- self . _recursiveLock . unlock ( )
120
+ self . _lock . unlock ( )
121
121
}
122
122
}
123
123
124
124
internal func handleFulfill( value: Value )
125
125
{
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 {
129
129
self . value. rawValue = value
130
130
self . _finish ( )
131
- self . _recursiveLock . unlock ( )
131
+ self . _lock . unlock ( )
132
132
}
133
133
else {
134
- self . _recursiveLock . unlock ( )
134
+ self . _lock . unlock ( )
135
135
}
136
136
}
137
137
138
138
internal func handleRejectInfo( errorInfo: ErrorInfo )
139
139
{
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 {
143
144
self . errorInfo. rawValue = errorInfo
144
145
self . _finish ( )
145
- self . _recursiveLock . unlock ( )
146
+ self . _lock . unlock ( )
146
147
}
147
148
else {
148
- self . _recursiveLock . unlock ( )
149
+ self . _lock . unlock ( )
149
150
}
150
151
}
151
152
152
153
internal func handlePause( ) -> Bool
153
154
{
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 {
156
158
self . configuration. pause ? ( )
157
- self . state. rawValue = . Paused
158
- self . _recursiveLock. unlock ( )
159
+ self . _lock. unlock ( )
159
160
return true
160
161
}
161
162
else {
162
- self . _recursiveLock . unlock ( )
163
+ self . _lock . unlock ( )
163
164
return false
164
165
}
165
166
}
166
167
167
168
internal func handleResume( ) -> Bool
168
169
{
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 } ) {
198
172
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 ( )
203
175
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 ( )
207
182
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
213
196
}
214
197
}
215
198
216
199
private func _handleResume( ) -> Bool
217
200
{
218
- if self . state. rawValue == . Paused {
201
+ let ( _, updated) = self . state. tryUpdate { $0 == . Paused ? ( . Running, true ) : ( $0, false ) }
202
+ if updated {
219
203
self . configuration. resume ? ( )
220
- self . state. rawValue = . Running
221
204
return true
222
205
}
223
206
else {
@@ -227,16 +210,16 @@ internal class _StateMachine<Progress, Value, Error>
227
210
228
211
internal func handleCancel( error: Error ? = nil ) -> Bool
229
212
{
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 {
233
216
self . errorInfo. rawValue = ErrorInfo ( error: error, isCancelled: true )
234
217
self . _finish ( )
235
- self . _recursiveLock . unlock ( )
218
+ self . _lock . unlock ( )
236
219
return true
237
220
}
238
221
else {
239
- self . _recursiveLock . unlock ( )
222
+ self . _lock . unlock ( )
240
223
return false
241
224
}
242
225
}
@@ -252,7 +235,7 @@ internal class _StateMachine<Progress, Value, Error>
252
235
253
236
self . configuration. finish ( )
254
237
255
- self . initResumeClosure = nil
238
+ self . initResumeClosure. rawValue = nil
256
239
self . progress. rawValue = nil
257
240
}
258
241
}
0 commit comments