internal void Close(ClosedChannelException cause) { if (this.inFail) { this.channel.EventLoop.Execute((buf, ex) => ((ChannelOutboundBuffer)buf).Close((ClosedChannelException)ex), this, cause); return; } this.inFail = true; if (this.channel.Open) { throw new InvalidOperationException("close() must be invoked after the channel is closed."); } if (!this.IsEmpty) { throw new InvalidOperationException("close() must be invoked after all flushed writes are handled."); } // Release all unflushed messages. try { Entry e = this.unflushedEntry; while (e != null) { // Just decrease; do not trigger any events via DecrementPendingOutboundBytes() int size = e.PendingSize; Interlocked.Add(ref this.totalPendingSize, -size); if (!e.Cancelled) { ReferenceCountUtil.SafeRelease(e.Message); Util.SafeSetFailure(e.Promise, cause, Logger); if (e.Promise != TaskCompletionSource.Void && !e.Promise.TrySetException(cause)) { Logger.Warn($"Failed to mark a promise as failure because it's done already: {e.Promise}", cause); } } e = e.RecycleAndGetNext(); } } finally { this.inFail = false; } this.ClearNioBuffers(); }
protected void Close(IPromise promise, Exception cause, ClosedChannelException closeCause, bool notify) { if (!promise.SetUncancellable()) { return; } var ch = _channel; if (SharedConstants.False < (uint)Interlocked.Exchange(ref ch.v_closeInitiated, SharedConstants.True)) { var closeCompletion = ch.CloseCompletion; if (closeCompletion.IsCompleted) { // Closed already. Util.SafeSetSuccess(promise, Logger); } else if (!promise.IsVoid) // Only needed if no VoidChannelPromise. { closeCompletion.LinkOutcome(promise); } return; } bool wasActive = ch.Active; var outboundBuffer = Interlocked.Exchange(ref _outboundBuffer, null); // Disallow adding any messages and flushes to outboundBuffer. IEventExecutor closeExecutor = PrepareToClose(); if (closeExecutor is object) { closeExecutor.Execute(() => { try { // Execute the close. DoClose0(promise); } finally { // Call invokeLater so closeAndDeregister is executed input the EventLoop again! InvokeLater(() => { if (outboundBuffer is object) { // Fail all the queued messages outboundBuffer.FailFlushed(cause, notify); outboundBuffer.Close(closeCause); } FireChannelInactiveAndDeregister(wasActive); }); } }); } else { try { // Close the channel and fail the queued messages input all cases. DoClose0(promise); } finally { if (outboundBuffer is object) { // Fail all the queued messages. outboundBuffer.FailFlushed(cause, notify); outboundBuffer.Close(closeCause); } } if (_inFlush0) { InvokeLater(() => FireChannelInactiveAndDeregister(wasActive)); } else { FireChannelInactiveAndDeregister(wasActive); } } }
internal void Close(ClosedChannelException cause) => this.Close(cause, false);