예제 #1
0
        IChannelHandler Replace(
            AbstractChannelHandlerContext ctx, IChannelHandler newHandler)
        {
            Contract.Requires(ctx != this.head && ctx != this.tail);

            lock (this.head)
            {
                var newCtx = new DefaultChannelHandlerContext(this, null, null, newHandler);

                CheckMultiplicity(newCtx);

                AbstractChannelHandlerContext prev = ctx.Prev;
                AbstractChannelHandlerContext next = ctx.Next;
                newCtx.Prev = prev;
                newCtx.Next = next;

                // Finish the replacement of oldCtx with newCtx in the linked list.
                // Note that this doesn't mean events will be sent to the new handler immediately
                // because we are currently at the event handler thread and no more than one handler methods can be invoked
                // at the same time (we ensured that in replace().)
                prev.Next = newCtx;
                next.Prev = newCtx;

                // update the reference to the replacement so forward of buffered content will work correctly
                ctx.Prev = newCtx;
                ctx.Next = newCtx;

                // Invoke newHandler.handlerAdded() first (i.e. before oldHandler.handlerRemoved() is invoked)
                // because callHandlerRemoved() will trigger inboundBufferUpdated() or flush() on newHandler and those
                // event handlers must be called after handlerAdded().
                this.CallHandlerAdded(newCtx);
                this.CallHandlerRemoved(ctx);
                return(ctx.Handler);
            }
        }
예제 #2
0
        public IChannelPipeline AddBefore(IChannelHandlerInvoker invoker, string baseName, string name, IChannelHandler handler)
        {
            IEventExecutor executor;
            AbstractChannelHandlerContext newCtx;
            AbstractChannelHandlerContext ctx;
            bool inEventLoop;

            lock (this)
            {
                CheckMultiplicity(handler);
                ctx = this.GetContextOrThrow(baseName);

                newCtx   = new DefaultChannelHandlerContext(this, invoker, this.FilterName(name, handler), handler);
                executor = this.ExecutorSafe(invoker);

                // If the executor is null it means that the channel was not registered on an eventloop yet.
                // In this case we add the context to the pipeline and add a task that will call
                // ChannelHandler.handlerAdded(...) once the channel is registered.
                if (executor == null)
                {
                    AddBefore0(ctx, newCtx);
                    this.CallHandlerCallbackLater(newCtx, true);
                    return(this);
                }

                inEventLoop = executor.InEventLoop;
                if (inEventLoop)
                {
                    AddBefore0(ctx, newCtx);
                }
            }

            if (inEventLoop)
            {
                this.CallHandlerAdded0(newCtx);
            }
            else
            {
                executor.SubmitAsync(() =>
                {
                    lock (this)
                    {
                        AddBefore0(ctx, newCtx);
                    }
                    this.CallHandlerAdded0(newCtx);
                    return(0);
                }).Wait();
            }
            return(this);
        }
예제 #3
0
        IChannelHandler Replace(AbstractChannelHandlerContext ctx, string newName, IChannelHandler newHandler)
        {
            Contract.Requires(ctx != this.head && ctx != this.tail);

            Task future;

            lock (this.head)
            {
                if (newName == null)
                {
                    newName = ctx.Name;
                }
                else if (!ctx.Name.Equals(newName, StringComparison.Ordinal))
                {
                    newName = this.FilterName(newName, newHandler);
                }

                var newCtx = new DefaultChannelHandlerContext(this, ctx.Invoker, newName, newHandler);

                if (!newCtx.Channel.Registered || newCtx.Executor.InEventLoop)
                {
                    this.ReplaceUnsafe(ctx, newName, newCtx);
                    return(ctx.Handler);
                }
                else
                {
                    string finalNewName = newName;
                    future = newCtx.Executor.SubmitAsync(
                        () =>
                    {
                        lock (this.head)
                        {
                            this.ReplaceUnsafe(ctx, finalNewName, newCtx);
                        }
                        return(TaskEx.Completed);
                    });
                }
            }

            // Run the following 'waiting' code outside of the above synchronized block
            // in order to avoid deadlock

            future.Wait();

            return(ctx.Handler);
        }
예제 #4
0
        public IChannelPipeline AddLast(IChannelHandler handler)
        {
            Contract.Requires(handler != null);

            var newCtx = new DefaultChannelHandlerContext(this, null, null, handler);

            CheckMultiplicity(newCtx);

            AbstractChannelHandlerContext prev = this.tail.Prev;

            newCtx.Prev    = prev;
            newCtx.Next    = this.tail;
            prev.Next      = newCtx;
            this.tail.Prev = newCtx;

            this.CallHandlerAdded(newCtx);
            return(this);
        }
예제 #5
0
        public IChannelPipeline AddFirst(IChannelHandler handler)
        {
            Contract.Requires(handler != null);

            lock (this.head)
            {
                var newCtx = new DefaultChannelHandlerContext(this, null, null, handler);
                CheckMultiplicity(newCtx);

                AbstractChannelHandlerContext nextCtx = this.head.Next;
                newCtx.Prev    = this.head;
                newCtx.Next    = nextCtx;
                this.head.Next = newCtx;
                nextCtx.Prev   = newCtx;

                this.CallHandlerAdded(newCtx);
            }
            return(this);
        }
예제 #6
0
        public IChannelPipeline AddFirst(IChannelHandlerInvoker invoker, string name, IChannelHandler handler)
        {
            Contract.Requires(handler != null);

            lock (this.head)
            {
                name = this.FilterName(name, handler);
                var newCtx = new DefaultChannelHandlerContext(this, invoker, name, handler);
                CheckMultiplicity(newCtx);

                AbstractChannelHandlerContext nextCtx = this.head.Next;
                newCtx.Prev    = this.head;
                newCtx.Next    = nextCtx;
                this.head.Next = newCtx;
                nextCtx.Prev   = newCtx;

                this.nameContextMap.Add(name, newCtx);

                this.CallHandlerAdded(newCtx);
            }
            return(this);
        }
예제 #7
0
        IChannelHandler Replace(AbstractChannelHandlerContext ctx, string newName, IChannelHandler newHandler)
        {
            Contract.Assert(ctx != this.head && ctx != this.tail);

            AbstractChannelHandlerContext newCtx;
            IEventExecutor executor;
            bool           inEventLoop;

            lock (this)
            {
                CheckMultiplicity(newHandler);

                if (newName == null)
                {
                    newName = ctx.Name;
                }
                else if (!ctx.Name.Equals(newName, StringComparison.Ordinal))
                {
                    newName = this.FilterName(newName, newHandler);
                }

                newCtx   = new DefaultChannelHandlerContext(this, ctx.invoker, newName, newHandler);
                executor = this.ExecutorSafe(ctx.invoker);

                // If the executor is null it means that the channel was not registered on an eventloop yet.
                // In this case we replace the context in the pipeline
                // and add a task that will call ChannelHandler.handlerAdded(...) and
                // ChannelHandler.handlerRemoved(...) once the channel is registered.
                if (executor == null)
                {
                    Replace0(ctx, newCtx);
                    this.CallHandlerCallbackLater(newCtx, true);
                    this.CallHandlerCallbackLater(ctx, false);
                    return(ctx.Handler);
                }
                inEventLoop = executor.InEventLoop;
                if (inEventLoop)
                {
                    Replace0(ctx, newCtx);
                }
            }

            if (inEventLoop)
            {
                // Invoke newHandler.handlerAdded() first (i.e. before oldHandler.handlerRemoved() is invoked)
                // because callHandlerRemoved() will trigger channelRead() or flush() on newHandler and those
                // event handlers must be called after handlerAdded().
                this.CallHandlerAdded0(newCtx);
                this.CallHandlerRemoved0(ctx);
            }
            else
            {
                executor.SubmitAsync(() =>
                {
                    lock (this)
                    {
                        Replace0(ctx, newCtx);
                    }
                    // Invoke newHandler.handlerAdded() first (i.e. before oldHandler.handlerRemoved() is invoked)
                    // because callHandlerRemoved() will trigger channelRead() or flush() on newHandler and
                    // those event handlers must be called after handlerAdded().
                    this.CallHandlerAdded0(newCtx);
                    this.CallHandlerRemoved0(ctx);
                    return(0);
                }).Wait();
            }

            return(ctx.Handler);
        }