Simplify DefaultChannelPipeline

This commit is contained in:
Trustin Lee 2013-01-09 19:13:43 +09:00
parent b742dcc209
commit b6fcf3acc4
3 changed files with 112 additions and 223 deletions

View File

@ -143,7 +143,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
private final Runnable nextCtxFireInboundBufferUpdatedTask = new Runnable() { private final Runnable nextCtxFireInboundBufferUpdatedTask = new Runnable() {
@Override @Override
public void run() { public void run() {
DefaultChannelHandlerContext next = nextContext( DefaultChannelHandlerContext next = findContextInbound(
DefaultChannelHandlerContext.this.next, FLAG_STATE_HANDLER); DefaultChannelHandlerContext.this.next, FLAG_STATE_HANDLER);
if (next != null) { if (next != null) {
next.fillBridge(); next.fillBridge();
@ -188,7 +188,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
} }
} }
DefaultChannelHandlerContext nextCtx = nextContext(ctx.next, FLAG_STATE_HANDLER); DefaultChannelHandlerContext nextCtx = findContextInbound(ctx.next, FLAG_STATE_HANDLER);
if (nextCtx != null) { if (nextCtx != null) {
nextCtx.callFreeInboundBuffer(); nextCtx.callFreeInboundBuffer();
} else { } else {
@ -218,7 +218,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
} }
} }
DefaultChannelHandlerContext nextCtx = prevContext(ctx.prev, FLAG_OPERATION_HANDLER); DefaultChannelHandlerContext nextCtx = findContextOutbound(ctx.prev, FLAG_OPERATION_HANDLER);
if (nextCtx != null) { if (nextCtx != null) {
nextCtx.callFreeOutboundBuffer(); nextCtx.callFreeOutboundBuffer();
} }
@ -941,17 +941,17 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
@Override @Override
public ByteBuf nextOutboundByteBuffer() { public ByteBuf nextOutboundByteBuffer() {
return pipeline.nextOutboundByteBuffer(prev); return pipeline.findOutboundByteBuffer(prev);
} }
@Override @Override
public MessageBuf<Object> nextOutboundMessageBuffer() { public MessageBuf<Object> nextOutboundMessageBuffer() {
return pipeline.nextOutboundMessageBuffer(prev); return pipeline.findOutboundMessageBuffer(prev);
} }
@Override @Override
public void fireChannelRegistered() { public void fireChannelRegistered() {
DefaultChannelHandlerContext next = nextContext(this.next, FLAG_STATE_HANDLER); DefaultChannelHandlerContext next = findContextInbound(this.next, FLAG_STATE_HANDLER);
if (next != null) { if (next != null) {
EventExecutor executor = next.executor(); EventExecutor executor = next.executor();
if (executor.inEventLoop()) { if (executor.inEventLoop()) {
@ -964,7 +964,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
@Override @Override
public void fireChannelUnregistered() { public void fireChannelUnregistered() {
DefaultChannelHandlerContext next = nextContext(this.next, FLAG_STATE_HANDLER); DefaultChannelHandlerContext next = findContextInbound(this.next, FLAG_STATE_HANDLER);
if (next != null) { if (next != null) {
EventExecutor executor = next.executor(); EventExecutor executor = next.executor();
if (executor.inEventLoop() && prev != null) { if (executor.inEventLoop() && prev != null) {
@ -977,7 +977,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
@Override @Override
public void fireChannelActive() { public void fireChannelActive() {
DefaultChannelHandlerContext next = nextContext(this.next, FLAG_STATE_HANDLER); DefaultChannelHandlerContext next = findContextInbound(this.next, FLAG_STATE_HANDLER);
if (next != null) { if (next != null) {
EventExecutor executor = next.executor(); EventExecutor executor = next.executor();
if (executor.inEventLoop()) { if (executor.inEventLoop()) {
@ -990,7 +990,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
@Override @Override
public void fireChannelInactive() { public void fireChannelInactive() {
DefaultChannelHandlerContext next = nextContext(this.next, FLAG_STATE_HANDLER); DefaultChannelHandlerContext next = findContextInbound(this.next, FLAG_STATE_HANDLER);
if (next != null) { if (next != null) {
EventExecutor executor = next.executor(); EventExecutor executor = next.executor();
if (executor.inEventLoop() && prev != null) { if (executor.inEventLoop() && prev != null) {
@ -1085,7 +1085,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
@Override @Override
public void fireInboundBufferSuspended() { public void fireInboundBufferSuspended() {
DefaultChannelHandlerContext next = nextContext(this.next, FLAG_STATE_HANDLER); DefaultChannelHandlerContext next = findContextInbound(this.next, FLAG_STATE_HANDLER);
if (next != null) { if (next != null) {
EventExecutor executor = next.executor(); EventExecutor executor = next.executor();
if (executor.inEventLoop() && prev != null) { if (executor.inEventLoop() && prev != null) {
@ -1138,7 +1138,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
@Override @Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) { public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return pipeline.bind(prevContext(prev, FLAG_OPERATION_HANDLER), localAddress, promise); return pipeline.bind(findContextOutbound(prev, FLAG_OPERATION_HANDLER), localAddress, promise);
} }
@Override @Override
@ -1148,34 +1148,35 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
@Override @Override
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) { public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
return pipeline.connect(prevContext(prev, FLAG_OPERATION_HANDLER), remoteAddress, localAddress, promise); return pipeline.connect(
findContextOutbound(prev, FLAG_OPERATION_HANDLER), remoteAddress, localAddress, promise);
} }
@Override @Override
public ChannelFuture disconnect(ChannelPromise promise) { public ChannelFuture disconnect(ChannelPromise promise) {
return pipeline.disconnect(prevContext(prev, FLAG_OPERATION_HANDLER), promise); return pipeline.disconnect(findContextOutbound(prev, FLAG_OPERATION_HANDLER), promise);
} }
@Override @Override
public ChannelFuture close(ChannelPromise promise) { public ChannelFuture close(ChannelPromise promise) {
return pipeline.close(prevContext(prev, FLAG_OPERATION_HANDLER), promise); return pipeline.close(findContextOutbound(prev, FLAG_OPERATION_HANDLER), promise);
} }
@Override @Override
public ChannelFuture deregister(ChannelPromise promise) { public ChannelFuture deregister(ChannelPromise promise) {
return pipeline.deregister(prevContext(prev, FLAG_OPERATION_HANDLER), promise); return pipeline.deregister(findContextOutbound(prev, FLAG_OPERATION_HANDLER), promise);
} }
@Override @Override
public void read() { public void read() {
pipeline.read(prevContext(prev, FLAG_OPERATION_HANDLER)); pipeline.read(findContextOutbound(prev, FLAG_OPERATION_HANDLER));
} }
@Override @Override
public ChannelFuture flush(final ChannelPromise promise) { public ChannelFuture flush(final ChannelPromise promise) {
EventExecutor executor = executor(); EventExecutor executor = executor();
if (executor.inEventLoop()) { if (executor.inEventLoop()) {
DefaultChannelHandlerContext prev = prevContext(this.prev, FLAG_OPERATION_HANDLER); DefaultChannelHandlerContext prev = findContextOutbound(this.prev, FLAG_OPERATION_HANDLER);
prev.fillBridge(); prev.fillBridge();
pipeline.flush(prev, promise); pipeline.flush(prev, promise);
} else { } else {
@ -1310,11 +1311,11 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
@Override @Override
public ChannelFuture sendFile(FileRegion region) { public ChannelFuture sendFile(FileRegion region) {
return pipeline.sendFile(prevContext(prev, FLAG_OPERATION_HANDLER), region, newPromise()); return pipeline.sendFile(findContextOutbound(prev, FLAG_OPERATION_HANDLER), region, newPromise());
} }
@Override @Override
public ChannelFuture sendFile(FileRegion region, ChannelPromise promise) { public ChannelFuture sendFile(FileRegion region, ChannelPromise promise) {
return pipeline.sendFile(prevContext(prev, FLAG_OPERATION_HANDLER), region, promise); return pipeline.sendFile(findContextOutbound(prev, FLAG_OPERATION_HANDLER), region, promise);
} }
} }

View File

@ -47,8 +47,7 @@ final class DefaultChannelPipeline implements ChannelPipeline {
private final Channel.Unsafe unsafe; private final Channel.Unsafe unsafe;
final DefaultChannelHandlerContext head; final DefaultChannelHandlerContext head;
private volatile DefaultChannelHandlerContext tail; final DefaultChannelHandlerContext tail;
private final DefaultChannelHandlerContext tailCtx;
private final Map<String, DefaultChannelHandlerContext> name2ctx = private final Map<String, DefaultChannelHandlerContext> name2ctx =
new HashMap<String, DefaultChannelHandlerContext>(4); new HashMap<String, DefaultChannelHandlerContext>(4);
@ -66,7 +65,7 @@ final class DefaultChannelPipeline implements ChannelPipeline {
} }
this.channel = channel; this.channel = channel;
tailCtx = new DefaultChannelHandlerContext( tail = new DefaultChannelHandlerContext(
this, null, null, null, generateName(TAIL_HANDLER), TAIL_HANDLER); this, null, null, null, generateName(TAIL_HANDLER), TAIL_HANDLER);
HeadHandler headHandler; HeadHandler headHandler;
@ -82,9 +81,8 @@ final class DefaultChannelPipeline implements ChannelPipeline {
} }
head = new DefaultChannelHandlerContext( head = new DefaultChannelHandlerContext(
this, null, null, tailCtx, generateName(headHandler), headHandler); this, null, null, tail, generateName(headHandler), headHandler);
tailCtx.prev = head; tail.prev = head;
tail = tailCtx;
unsafe = channel.unsafe(); unsafe = channel.unsafe();
} }
@ -101,16 +99,14 @@ final class DefaultChannelPipeline implements ChannelPipeline {
@Override @Override
public ChannelPipeline addFirst(EventExecutorGroup group, final String name, ChannelHandler handler) { public ChannelPipeline addFirst(EventExecutorGroup group, final String name, ChannelHandler handler) {
final DefaultChannelHandlerContext nextCtx;
final DefaultChannelHandlerContext newCtx; final DefaultChannelHandlerContext newCtx;
synchronized (this) { synchronized (this) {
checkDuplicateName(name); checkDuplicateName(name);
nextCtx = head.next; newCtx = new DefaultChannelHandlerContext(this, group, null, null, name, handler);
newCtx = new DefaultChannelHandlerContext(this, group, head, nextCtx, name, handler);
if (!newCtx.channel().isRegistered() || newCtx.executor().inEventLoop()) { if (!newCtx.channel().isRegistered() || newCtx.executor().inEventLoop()) {
addFirst0(name, nextCtx, newCtx); addFirst0(name, newCtx);
return this; return this;
} }
} }
@ -123,7 +119,7 @@ final class DefaultChannelPipeline implements ChannelPipeline {
public void run() { public void run() {
synchronized (DefaultChannelPipeline.this) { synchronized (DefaultChannelPipeline.this) {
checkDuplicateName(name); checkDuplicateName(name);
addFirst0(name, nextCtx, newCtx); addFirst0(name, newCtx);
} }
} }
}); });
@ -131,19 +127,14 @@ final class DefaultChannelPipeline implements ChannelPipeline {
return this; return this;
} }
private void addFirst0( private void addFirst0(String name, DefaultChannelHandlerContext newCtx) {
final String name, DefaultChannelHandlerContext nextCtx, DefaultChannelHandlerContext newCtx) {
callBeforeAdd(newCtx); callBeforeAdd(newCtx);
if (nextCtx != null) { DefaultChannelHandlerContext nextCtx = head.next;
nextCtx.prev = newCtx;
}
if (head.next == tailCtx) {
tail = newCtx;
newCtx.next = tailCtx;
tailCtx.prev = newCtx;
}
head.next = newCtx; head.next = newCtx;
newCtx.prev = head;
newCtx.next = nextCtx;
nextCtx.prev = newCtx;
name2ctx.put(name, newCtx); name2ctx.put(name, newCtx);
@ -157,16 +148,14 @@ final class DefaultChannelPipeline implements ChannelPipeline {
@Override @Override
public ChannelPipeline addLast(EventExecutorGroup group, final String name, ChannelHandler handler) { public ChannelPipeline addLast(EventExecutorGroup group, final String name, ChannelHandler handler) {
final DefaultChannelHandlerContext oldTail; final DefaultChannelHandlerContext newCtx;
final DefaultChannelHandlerContext newTail;
synchronized (this) { synchronized (this) {
checkDuplicateName(name); checkDuplicateName(name);
oldTail = tail; newCtx = new DefaultChannelHandlerContext(this, group, null, null, name, handler);
newTail = new DefaultChannelHandlerContext(this, group, null, null, name, handler); if (!newCtx.channel().isRegistered() || newCtx.executor().inEventLoop()) {
if (!newTail.channel().isRegistered() || newTail.executor().inEventLoop()) { addLast0(name, newCtx);
addLast0(name, oldTail, newTail);
return this; return this;
} }
} }
@ -174,42 +163,32 @@ final class DefaultChannelPipeline implements ChannelPipeline {
// Run the following 'waiting' code outside of the above synchronized block // Run the following 'waiting' code outside of the above synchronized block
// in order to avoid deadlock // in order to avoid deadlock
newTail.executeOnEventLoop(new Runnable() { newCtx.executeOnEventLoop(new Runnable() {
@Override @Override
public void run() { public void run() {
synchronized (DefaultChannelPipeline.this) { synchronized (DefaultChannelPipeline.this) {
checkDuplicateName(name); checkDuplicateName(name);
addLast0(name, oldTail, newTail); addLast0(name, newCtx);
}
} }
}); }
});
return this; return this;
} }
private void addLast0( private void addLast0(
final String name, DefaultChannelHandlerContext oldTail, DefaultChannelHandlerContext newTail) { final String name, DefaultChannelHandlerContext newCtx) {
callBeforeAdd(newTail); callBeforeAdd(newCtx);
DefaultChannelHandlerContext prev = oldTail.prev; DefaultChannelHandlerContext prev = tail.prev;
if (oldTail == tailCtx) { prev.next = newCtx;
// This is the first handler added newCtx.prev = prev;
tailCtx.prev = newTail; newCtx.next = tail;
newTail.next = tailCtx; tail.prev = newCtx;
prev.next = newTail;
newTail.prev = prev;
} else {
oldTail.next = newTail;
newTail.prev = oldTail;
prev.next = oldTail; name2ctx.put(name, newCtx);
oldTail.prev = prev;
}
tail = newTail; callAfterAdd(newCtx);
name2ctx.put(name, newTail);
callAfterAdd(newTail);
} }
@Override @Override
@ -273,11 +252,8 @@ final class DefaultChannelPipeline implements ChannelPipeline {
synchronized (this) { synchronized (this) {
ctx = getContextOrDie(baseName); ctx = getContextOrDie(baseName);
if (ctx == tail) {
return addLast(name, handler);
}
checkDuplicateName(name); checkDuplicateName(name);
newCtx = new DefaultChannelHandlerContext(this, group, ctx, ctx.next, name, handler); newCtx = new DefaultChannelHandlerContext(this, group, null, null, name, handler);
if (!newCtx.channel().isRegistered() || newCtx.executor().inEventLoop()) { if (!newCtx.channel().isRegistered() || newCtx.executor().inEventLoop()) {
addAfter0(name, ctx, newCtx); addAfter0(name, ctx, newCtx);
@ -306,8 +282,11 @@ final class DefaultChannelPipeline implements ChannelPipeline {
callBeforeAdd(newCtx); callBeforeAdd(newCtx);
newCtx.prev = ctx;
newCtx.next = ctx.next;
ctx.next.prev = newCtx; ctx.next.prev = newCtx;
ctx.next = newCtx; ctx.next = newCtx;
name2ctx.put(name, newCtx); name2ctx.put(name, newCtx);
callAfterAdd(newCtx); callAfterAdd(newCtx);
@ -391,52 +370,25 @@ final class DefaultChannelPipeline implements ChannelPipeline {
} }
private DefaultChannelHandlerContext remove(final DefaultChannelHandlerContext ctx) { private DefaultChannelHandlerContext remove(final DefaultChannelHandlerContext ctx) {
assert ctx != head && ctx != tail;
DefaultChannelHandlerContext context; DefaultChannelHandlerContext context;
Future<?> future; Future<?> future;
synchronized (this) { synchronized (this) {
if (ctx == tailCtx) { if (!ctx.channel().isRegistered() || ctx.executor().inEventLoop()) {
throw new NoSuchElementException(); remove0(ctx);
} return ctx;
if (head == tail) {
return null;
} else if (ctx == head) {
throw new Error(); // Should never happen.
} else if (ctx == tail) {
if (tail == tailCtx) {
throw new NoSuchElementException();
}
final DefaultChannelHandlerContext oldTail = tail;
if (!oldTail.channel().isRegistered() || oldTail.executor().inEventLoop()) {
removeLast0(oldTail);
return oldTail;
} else {
future = oldTail.executor().submit(new Runnable() {
@Override
public void run() {
synchronized (DefaultChannelPipeline.this) {
removeLast0(oldTail);
}
}
});
context = oldTail;
}
} else { } else {
if (!ctx.channel().isRegistered() || ctx.executor().inEventLoop()) { future = ctx.executor().submit(new Runnable() {
remove0(ctx); @Override
return ctx; public void run() {
} else { synchronized (DefaultChannelPipeline.this) {
future = ctx.executor().submit(new Runnable() { remove0(ctx);
@Override }
public void run() { }
synchronized (DefaultChannelPipeline.this) { });
remove0(ctx); context = ctx;
}
}
});
context = ctx;
}
} }
} }
@ -462,7 +414,7 @@ final class DefaultChannelPipeline implements ChannelPipeline {
@Override @Override
public ChannelHandler removeFirst() { public ChannelHandler removeFirst() {
if (head.next == tailCtx) { if (head.next == tail) {
throw new NoSuchElementException(); throw new NoSuchElementException();
} }
return remove(head.next).handler(); return remove(head.next).handler();
@ -470,44 +422,10 @@ final class DefaultChannelPipeline implements ChannelPipeline {
@Override @Override
public ChannelHandler removeLast() { public ChannelHandler removeLast() {
final DefaultChannelHandlerContext oldTail; if (head.next == tail) {
throw new NoSuchElementException();
synchronized (this) {
if (tail == tailCtx) {
throw new NoSuchElementException();
}
oldTail = tail;
if (!oldTail.channel().isRegistered() || oldTail.executor().inEventLoop()) {
removeLast0(oldTail);
return oldTail.handler();
}
} }
return remove(tail.prev).handler();
// Run the following 'waiting' code outside of the above synchronized block
// in order to avoid deadlock
oldTail.executeOnEventLoop(new Runnable() {
@Override
public void run() {
synchronized (DefaultChannelPipeline.this) {
removeLast0(oldTail);
}
}
});
return oldTail.handler();
}
private void removeLast0(DefaultChannelHandlerContext oldTail) {
callBeforeRemove(oldTail);
tailCtx.prev = oldTail.prev;
oldTail.prev.next = tailCtx;
tail = oldTail.prev;
name2ctx.remove(oldTail.name());
callBeforeRemove(oldTail);
} }
@Override @Override
@ -530,63 +448,31 @@ final class DefaultChannelPipeline implements ChannelPipeline {
private ChannelHandler replace( private ChannelHandler replace(
final DefaultChannelHandlerContext ctx, final String newName, ChannelHandler newHandler) { final DefaultChannelHandlerContext ctx, final String newName, ChannelHandler newHandler) {
assert ctx != head && ctx != tail;
Future<?> future; Future<?> future;
synchronized (this) { synchronized (this) {
if (ctx == tailCtx) { boolean sameName = ctx.name().equals(newName);
throw new NoSuchElementException(); if (!sameName) {
checkDuplicateName(newName);
} }
if (ctx == head) {
throw new IllegalArgumentException();
} else if (ctx == tail) {
if (tail == tailCtx) {
throw new NoSuchElementException();
}
final DefaultChannelHandlerContext oldTail = tail;
final DefaultChannelHandlerContext newTail =
new DefaultChannelHandlerContext(this, null, oldTail, null, newName, newHandler);
if (!oldTail.channel().isRegistered() || oldTail.executor().inEventLoop()) { final DefaultChannelHandlerContext newCtx =
removeLast0(oldTail); new DefaultChannelHandlerContext(this, ctx.executor, null, null, newName, newHandler);
checkDuplicateName(newName);
addLast0(newName, tail, newTail); if (!newCtx.channel().isRegistered() || newCtx.executor().inEventLoop()) {
return ctx.handler(); replace0(ctx, newName, newCtx);
} else { return ctx.handler();
future = oldTail.executor().submit(new Runnable() {
@Override
public void run() {
synchronized (DefaultChannelPipeline.this) {
removeLast0(oldTail);
checkDuplicateName(newName);
addLast0(newName, tail, newTail);
}
}
});
}
} else { } else {
boolean sameName = ctx.name().equals(newName); future = newCtx.executor().submit(new Runnable() {
if (!sameName) { @Override
checkDuplicateName(newName); public void run() {
} synchronized (DefaultChannelPipeline.this) {
replace0(ctx, newName, newCtx);
DefaultChannelHandlerContext prev = ctx.prev; }
DefaultChannelHandlerContext next = ctx.next; }
});
final DefaultChannelHandlerContext newCtx =
new DefaultChannelHandlerContext(this, ctx.executor, prev, next, newName, newHandler);
if (!newCtx.channel().isRegistered() || newCtx.executor().inEventLoop()) {
replace0(ctx, newName, newCtx);
return ctx.handler();
} else {
future = newCtx.executor().submit(new Runnable() {
@Override
public void run() {
synchronized (DefaultChannelPipeline.this) {
replace0(ctx, newName, newCtx);
}
}
});
}
} }
} }
@ -607,6 +493,8 @@ final class DefaultChannelPipeline implements ChannelPipeline {
callBeforeRemove(ctx); callBeforeRemove(ctx);
callBeforeAdd(newCtx); callBeforeAdd(newCtx);
newCtx.prev = prev;
newCtx.next = next;
prev.next = newCtx; prev.next = newCtx;
next.prev = newCtx; next.prev = newCtx;
@ -729,8 +617,8 @@ final class DefaultChannelPipeline implements ChannelPipeline {
@Override @Override
public ChannelHandler last() { public ChannelHandler last() {
DefaultChannelHandlerContext last = tail; DefaultChannelHandlerContext last = tail.prev;
if (last == tailCtx || last == null) { if (last == head) {
return null; return null;
} }
return last.handler(); return last.handler();
@ -738,8 +626,8 @@ final class DefaultChannelPipeline implements ChannelPipeline {
@Override @Override
public ChannelHandlerContext lastContext() { public ChannelHandlerContext lastContext() {
DefaultChannelHandlerContext last = tail; DefaultChannelHandlerContext last = tail.prev;
if (last == head || last == null) { if (last == head) {
return null; return null;
} }
return last; return last;
@ -834,7 +722,7 @@ final class DefaultChannelPipeline implements ChannelPipeline {
Map<String, ChannelHandler> map = new LinkedHashMap<String, ChannelHandler>(); Map<String, ChannelHandler> map = new LinkedHashMap<String, ChannelHandler>();
DefaultChannelHandlerContext ctx = head.next; DefaultChannelHandlerContext ctx = head.next;
for (;;) { for (;;) {
if (ctx == null || ctx == tailCtx) { if (ctx == tail) {
return map; return map;
} }
map.put(ctx.name(), ctx.handler()); map.put(ctx.name(), ctx.handler());
@ -863,7 +751,7 @@ final class DefaultChannelPipeline implements ChannelPipeline {
buf.append(')'); buf.append(')');
ctx = ctx.next; ctx = ctx.next;
if (ctx == null) { if (ctx == tail) {
break; break;
} }
@ -887,15 +775,15 @@ final class DefaultChannelPipeline implements ChannelPipeline {
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> MessageBuf<T> outboundMessageBuffer() { public <T> MessageBuf<T> outboundMessageBuffer() {
return (MessageBuf<T>) nextOutboundMessageBuffer(tail); return (MessageBuf<T>) findOutboundMessageBuffer(tail.prev);
} }
@Override @Override
public ByteBuf outboundByteBuffer() { public ByteBuf outboundByteBuffer() {
return nextOutboundByteBuffer(tail); return findOutboundByteBuffer(tail.prev);
} }
ByteBuf nextOutboundByteBuffer(DefaultChannelHandlerContext ctx) { ByteBuf findOutboundByteBuffer(DefaultChannelHandlerContext ctx) {
final DefaultChannelHandlerContext initialCtx = ctx; final DefaultChannelHandlerContext initialCtx = ctx;
final Thread currentThread = Thread.currentThread(); final Thread currentThread = Thread.currentThread();
for (;;) { for (;;) {
@ -931,7 +819,7 @@ final class DefaultChannelPipeline implements ChannelPipeline {
} }
} }
MessageBuf<Object> nextOutboundMessageBuffer(DefaultChannelHandlerContext ctx) { MessageBuf<Object> findOutboundMessageBuffer(DefaultChannelHandlerContext ctx) {
final DefaultChannelHandlerContext initialCtx = ctx; final DefaultChannelHandlerContext initialCtx = ctx;
final Thread currentThread = Thread.currentThread(); final Thread currentThread = Thread.currentThread();
for (;;) { for (;;) {
@ -1333,7 +1221,7 @@ final class DefaultChannelPipeline implements ChannelPipeline {
if (message instanceof FileRegion) { if (message instanceof FileRegion) {
return sendFile((FileRegion) message, promise); return sendFile((FileRegion) message, promise);
} }
return write(tail, message, promise); return write(tail.prev, message, promise);
} }
ChannelFuture write(DefaultChannelHandlerContext ctx, final Object message, final ChannelPromise promise) { ChannelFuture write(DefaultChannelHandlerContext ctx, final Object message, final ChannelPromise promise) {
@ -1425,10 +1313,10 @@ final class DefaultChannelPipeline implements ChannelPipeline {
} }
DefaultChannelHandlerContext lastContext(int flag) { DefaultChannelHandlerContext lastContext(int flag) {
return prevContext(tail, flag); return findContextOutbound(tail.prev, flag);
} }
static DefaultChannelHandlerContext nextContext(DefaultChannelHandlerContext ctx, int flag) { static DefaultChannelHandlerContext findContextInbound(DefaultChannelHandlerContext ctx, int flag) {
if (ctx == null) { if (ctx == null) {
return null; return null;
} }
@ -1443,7 +1331,7 @@ final class DefaultChannelPipeline implements ChannelPipeline {
return realCtx; return realCtx;
} }
static DefaultChannelHandlerContext prevContext(DefaultChannelHandlerContext ctx, int flag) { static DefaultChannelHandlerContext findContextOutbound(DefaultChannelHandlerContext ctx, int flag) {
if (ctx == null) { if (ctx == null) {
return null; return null;
} }

View File

@ -214,7 +214,7 @@ public class DefaultChannelPipelineTest {
private static void verifyContextNumber(DefaultChannelPipeline pipeline, int expectedNumber) { private static void verifyContextNumber(DefaultChannelPipeline pipeline, int expectedNumber) {
DefaultChannelHandlerContext ctx = (DefaultChannelHandlerContext) pipeline.firstContext(); DefaultChannelHandlerContext ctx = (DefaultChannelHandlerContext) pipeline.firstContext();
int handlerNumber = 0; int handlerNumber = 0;
while (ctx != null) { while (ctx != pipeline.tail) {
handlerNumber++; handlerNumber++;
ctx = ctx.next; ctx = ctx.next;
} }