[#1442] Make sure closing the channel will not cause an UnsupportedOperationException

This commit is contained in:
Norman Maurer 2013-06-13 18:10:56 +02:00
parent e5ca6518ba
commit a1a86b9de4
2 changed files with 13 additions and 11 deletions

View File

@ -125,7 +125,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
DefaultChannelHandlerContext prev = this.prev;
if (prev != null) {
synchronized (pipeline) {
pipeline.remove0(this);
pipeline.remove0(this, true);
}
prev.teardown();
}

View File

@ -316,14 +316,14 @@ final class DefaultChannelPipeline implements ChannelPipeline {
synchronized (this) {
if (!ctx.channel().isRegistered() || ctx.executor().inEventLoop()) {
remove0(ctx);
remove0(ctx, false);
return ctx;
} else {
future = ctx.executor().submit(new Runnable() {
@Override
public void run() {
synchronized (DefaultChannelPipeline.this) {
remove0(ctx);
remove0(ctx, false);
}
}
});
@ -339,13 +339,13 @@ final class DefaultChannelPipeline implements ChannelPipeline {
return context;
}
void remove0(DefaultChannelHandlerContext ctx) {
void remove0(DefaultChannelHandlerContext ctx, boolean tearDown) {
DefaultChannelHandlerContext prev = ctx.prev;
DefaultChannelHandlerContext next = ctx.next;
prev.next = next;
next.prev = prev;
name2ctx.remove(ctx.name());
callHandlerRemoved(ctx);
callHandlerRemoved(ctx, tearDown);
}
@Override
@ -450,7 +450,7 @@ final class DefaultChannelPipeline implements ChannelPipeline {
// because callHandlerRemoved() will trigger inboundBufferUpdated() or flush() on newHandler and those
// event handlers must be called after handlerAdded().
callHandlerAdded(newCtx);
callHandlerRemoved(oldCtx);
callHandlerRemoved(oldCtx, false);
}
private static void checkMultiplicity(ChannelHandlerContext ctx) {
@ -505,24 +505,26 @@ final class DefaultChannelPipeline implements ChannelPipeline {
}
}
private void callHandlerRemoved(final DefaultChannelHandlerContext ctx) {
private void callHandlerRemoved(final DefaultChannelHandlerContext ctx, final boolean tearDown) {
if (ctx.channel().isRegistered() && !ctx.executor().inEventLoop()) {
ctx.executor().execute(new Runnable() {
@Override
public void run() {
callHandlerRemoved0(ctx);
callHandlerRemoved0(ctx, tearDown);
}
});
return;
}
callHandlerRemoved0(ctx);
callHandlerRemoved0(ctx, tearDown);
}
private void callHandlerRemoved0(final DefaultChannelHandlerContext ctx) {
private void callHandlerRemoved0(final DefaultChannelHandlerContext ctx, boolean tearDown) {
// Notify the complete removal.
try {
ctx.handler().handlerRemoved(ctx);
ctx.setRemoved();
if (!tearDown) {
ctx.setRemoved();
}
} catch (Throwable t) {
fireExceptionCaught(new ChannelPipelineException(
ctx.handler().getClass().getName() + ".handlerRemoved() has thrown an exception.", t));