예제 #1
0
        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();
        }
예제 #2
0
            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);
                    }
                }
            }
예제 #3
0
 internal void Close(ClosedChannelException cause) => this.Close(cause, false);