@@ -24,12 +24,14 @@ private struct SocketChannelLifecycleManager {
2424 case fresh
2525 case preRegistered // register() has been run but the selector doesn't know about it yet
2626 case fullyRegistered // fully registered, ie. the selector knows about it
27- case activated
27+ case preActivation // activated, but we have not fired channelActivated yet
28+ case fullyActivated // fully activated, i.e., the signal has been fired
2829 case closed
2930 }
3031
3132 private enum Event {
32- case activate
33+ case beginActivation
34+ case finishActivation
3335 case beginRegistration
3436 case finishRegistration
3537 case close
@@ -52,9 +54,11 @@ private struct SocketChannelLifecycleManager {
5254 didSet {
5355 self . eventLoop. assertInEventLoop ( )
5456 switch ( oldValue, self . currentState) {
55- case ( _, . activated ) :
57+ case ( _, . preActivation ) :
5658 self . isActiveAtomic. store ( true , ordering: . relaxed)
57- case ( . activated, _) :
59+ case ( . preActivation, . fullyActivated) :
60+ ( ) // Stay active
61+ case ( . preActivation, _) , ( . fullyActivated, _) :
5862 self . isActiveAtomic. store ( false , ordering: . relaxed)
5963 default :
6064 ( )
@@ -99,8 +103,13 @@ private struct SocketChannelLifecycleManager {
99103
100104 // we need to return a closure here and to not suffer from a potential allocation for that this must be inlined
101105 @inline ( __always)
102- internal mutating func activate( ) -> ( ( EventLoopPromise < Void > ? , ChannelPipeline ) -> Void ) {
103- self . moveState ( event: . activate)
106+ internal mutating func beginActivation( ) -> ( ( EventLoopPromise < Void > ? , ChannelPipeline ) -> Void ) {
107+ self . moveState ( event: . beginActivation)
108+ }
109+
110+ @inline ( __always)
111+ internal mutating func finishActivation( ) -> ( ( EventLoopPromise < Void > ? , ChannelPipeline ) -> Void ) {
112+ self . moveState ( event: . finishActivation)
104113 }
105114
106115 // MARK: private API
@@ -132,11 +141,10 @@ private struct SocketChannelLifecycleManager {
132141 }
133142
134143 // origin: .fullyRegistered
135- case ( . fullyRegistered, . activate ) :
136- self . currentState = . activated
144+ case ( . fullyRegistered, . beginActivation ) :
145+ self . currentState = . preActivation
137146 return { promise, pipeline in
138147 promise? . succeed ( ( ) )
139- pipeline. syncOperations. fireChannelActive ( )
140148 }
141149
142150 // origin: .preRegistered || .fullyRegistered
@@ -147,29 +155,61 @@ private struct SocketChannelLifecycleManager {
147155 pipeline. syncOperations. fireChannelUnregistered ( )
148156 }
149157
150- // origin: .activated
151- case ( . activated, . close) :
158+ // origin: .preActivation
159+ case ( . preActivation, . finishActivation) :
160+ self . currentState = . fullyActivated
161+ return { promise, pipeline in
162+ assert ( promise == nil )
163+ pipeline. syncOperations. fireChannelActive ( )
164+ }
165+
166+ case ( . preActivation, . close) :
167+ self . currentState = . closed
168+ return { promise, pipeline in
169+ promise? . succeed ( ( ) )
170+ // Don't fire channelInactive here.
171+ pipeline. syncOperations. fireChannelUnregistered ( )
172+ }
173+
174+ case ( . preActivation, . beginActivation) where self . supportsReconnect:
175+ return { promise, pipeline in
176+ promise? . succeed ( ( ) )
177+ }
178+
179+ // origin: .fullyActivated
180+ case ( . fullyActivated, . close) :
152181 self . currentState = . closed
153182 return { promise, pipeline in
154183 promise? . succeed ( ( ) )
155184 pipeline. syncOperations. fireChannelInactive ( )
156185 pipeline. syncOperations. fireChannelUnregistered ( )
157186 }
158187
159- // origin: .activated
160- case ( . activated, . activate) where self . supportsReconnect:
188+ case ( . fullyActivated, . beginActivation) where self . supportsReconnect:
161189 return { promise, pipeline in
162190 promise? . succeed ( ( ) )
163191 }
164192
193+ case ( . fullyActivated, . finishActivation) where self . supportsReconnect:
194+ return { promise, pipeline in
195+ assert ( promise == nil )
196+ }
197+
165198 // bad transitions
166- case ( . fresh, . activate) , // should go through .registered first
167- ( . preRegistered, . activate) , // need to first be fully registered
199+ case ( . fresh, . beginActivation) , // should go through .registered first
200+ ( . fresh, . finishActivation) , // should go through .registerd first
201+ ( . preRegistered, . beginActivation) , // need to first be fully registered
202+ ( . preRegistered, . finishActivation) , // need to first be fully registered
168203 ( . preRegistered, . beginRegistration) , // already registered
169204 ( . fullyRegistered, . beginRegistration) , // already registered
170- ( . activated, . activate) , // already activated
171- ( . activated, . beginRegistration) , // already fully registered (and activated)
172- ( . activated, . finishRegistration) , // already fully registered (and activated)
205+ ( . fullyRegistered, . finishActivation) , // need to activate first
206+ ( . preActivation, . beginActivation) , // already activated
207+ ( . preActivation, . beginRegistration) , // already fully registered (and activated)
208+ ( . preActivation, . finishRegistration) , // already fully registered (and activated)
209+ ( . fullyActivated, . beginActivation) , // need to activate first
210+ ( . fullyActivated, . beginRegistration) , // already fully registered
211+ ( . fullyActivated, . finishRegistration) , // already fully registered
212+ ( . fullyActivated, . finishActivation) , // already signaled
173213 ( . fullyRegistered, . finishRegistration) , // already fully registered
174214 ( . fresh, . finishRegistration) , // need to register lazily first
175215 ( . closed, _) : // already closed
@@ -184,15 +224,20 @@ private struct SocketChannelLifecycleManager {
184224 // MARK: convenience properties
185225 internal var isActive : Bool {
186226 self . eventLoop. assertInEventLoop ( )
187- return self . currentState == . activated
227+ switch self . currentState {
228+ case . preActivation, . fullyActivated:
229+ return true
230+ case . fresh, . preRegistered, . fullyRegistered, . closed:
231+ return false
232+ }
188233 }
189234
190235 internal var isPreRegistered : Bool {
191236 self . eventLoop. assertInEventLoop ( )
192237 switch self . currentState {
193238 case . fresh, . closed:
194239 return false
195- case . preRegistered, . fullyRegistered, . activated :
240+ case . preRegistered, . fullyRegistered, . preActivation , . fullyActivated :
196241 return true
197242 }
198243 }
@@ -202,7 +247,7 @@ private struct SocketChannelLifecycleManager {
202247 switch self . currentState {
203248 case . fresh, . closed, . preRegistered:
204249 return false
205- case . fullyRegistered, . activated :
250+ case . fullyRegistered, . preActivation , . fullyActivated :
206251 return true
207252 }
208253 }
@@ -1366,7 +1411,13 @@ class BaseSocketChannel<SocketType: BaseSocketProtocol>: SelectableChannel, Chan
13661411 return
13671412 }
13681413 }
1369- self . lifecycleManager. activate ( ) ( promise, self . pipeline)
1414+ self . lifecycleManager. beginActivation ( ) ( promise, self . pipeline)
1415+ guard self . lifecycleManager. isActive else {
1416+ // the channel got closed in the promise succeed closure
1417+ return
1418+ }
1419+ // if the channel wasn't closed, continue to fully activate
1420+ self . lifecycleManager. finishActivation ( ) ( nil , self . pipeline)
13701421 guard self . lifecycleManager. isOpen else {
13711422 // in the user callout for `channelActive` the channel got closed.
13721423 return
0 commit comments