void RunFinishPeerReadTask(LocalChannel peer) { // If the peer is writing, we must wait until after reads are completed for that peer before we can read. So // we keep track of the task, and coordinate later that our read can't happen until the peer is done. try { if (peer.writeInProgress) { peer.finishReadFuture = peer.EventLoop.SubmitAsync( () => { this.FinishPeerRead0(peer); return((object)null); }); } else { peer.EventLoop.Execute(() => this.FinishPeerRead0(peer)); } } catch (Exception cause) { Logger.Warn("Closing Local channels {}-{} because exception occurred!", this, peer, cause); this.CloseAsync(); peer.CloseAsync(); throw; } }
protected override void DoClose() { var peer = this.peer; var oldState = this.state; try { if (oldState != State.Closed) { // Update all internal state before the closeFuture is notified. if (this.localAddress != null) { if (this.Parent == null) { LocalChannelRegistry.Unregister(this.localAddress); } this.localAddress = null; } // State change must happen before finishPeerRead to ensure writes are released either in doWrite or // channelRead. this.state = State.Closed; // Preserve order of event and force a read operation now before the close operation is processed. this.FinishPeerRead(this); TaskCompletionSource promise = this.connectPromise; if (promise != null) { // Use tryFailure() instead of setFailure() to avoid the race against cancel(). promise.TrySetException(DoCloseClosedChannelException); this.connectPromise = null; } } if (peer != null) { this.peer = null; // Need to execute the close in the correct EventLoop (see https://github.com/netty/netty/issues/1777). // Also check if the registration was not done yet. In this case we submit the close to the EventLoop // to make sure its run after the registration completes // (see https://github.com/netty/netty/issues/2144). IEventLoop peerEventLoop = peer.EventLoop; bool peerIsActive = peer.Active; if (peerEventLoop.InEventLoop && !this.registerInProgress) { peer.TryClose(peerIsActive); } else { try { peerEventLoop.Execute(() => peer.TryClose(peerIsActive)); } catch (Exception cause) { Logger.Warn("Releasing Inbound Queues for channels {}-{} because exception occurred!", this, peer, cause); if (peerEventLoop.InEventLoop) { peer.ReleaseInboundBuffers(); } else { // inboundBuffers is a SPSC so we may leak if the event loop is shutdown prematurely or // rejects the close Runnable but give a best effort. peer.CloseAsync(); } throw; } } } } finally { // Release all buffers if the Channel was already registered in the past and if it was not closed before. if (oldState != State.Closed) { // We need to release all the buffers that may be put into our inbound queue since we closed the Channel // to ensure we not leak any memory. This is fine as it basically gives the same guarantees as TCP which // means even if the promise was notified before its not really guaranteed that the "remote peer" will // see the buffer at all. this.ReleaseInboundBuffers(); } } }