Fix a bug where timeout handlers sometimes generate events too early

This commit is contained in:
Trustin Lee 2012-06-18 13:38:59 +09:00
parent faf529166f
commit 7a4e374294
2 changed files with 37 additions and 12 deletions

View File

@ -129,7 +129,7 @@ public class IdleStateHandler extends ChannelHandlerAdapter {
volatile ScheduledFuture<?> allIdleTimeout;
int allIdleCount;
volatile boolean destroyed;
private volatile int state; // 0 - none, 1 - initialized, 2 - destroyed
/**
* Creates a new instance.
@ -202,12 +202,12 @@ public class IdleStateHandler extends ChannelHandlerAdapter {
@Override
public void beforeAdd(ChannelHandlerContext ctx) throws Exception {
if (ctx.channel().isActive()) {
if (ctx.channel().isActive() & ctx.channel().isRegistered()) {
// channelActvie() event has been fired already, which means this.channelActive() will
// not be invoked. We have to initialize here instead.
initialize(ctx);
} else {
// channelActive() event has not been fired yet. this.channelOpen() will be invoked
// channelActive() event has not been fired yet. this.channelActive() will be invoked
// and initialization will occur there.
}
}
@ -217,6 +217,15 @@ public class IdleStateHandler extends ChannelHandlerAdapter {
destroy();
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
// Initialize early if channel is active already.
if (ctx.channel().isActive()) {
initialize(ctx);
}
super.channelRegistered(ctx);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// This method will be invoked only if this handler was added
@ -256,10 +265,14 @@ public class IdleStateHandler extends ChannelHandlerAdapter {
private void initialize(ChannelHandlerContext ctx) {
// Avoid the case where destroy() is called before scheduling timeouts.
// See: https://github.com/netty/netty/issues/143
if (destroyed) {
switch (state) {
case 1:
case 2:
return;
}
state = 1;
EventExecutor loop = ctx.executor();
lastReadTime = lastWriteTime = System.currentTimeMillis();
@ -281,7 +294,7 @@ public class IdleStateHandler extends ChannelHandlerAdapter {
}
private void destroy() {
destroyed = true;
state = 2;
if (readerIdleTimeout != null) {
readerIdleTimeout.cancel(false);

View File

@ -74,7 +74,7 @@ public class ReadTimeoutHandler extends ChannelStateHandlerAdapter {
private volatile ScheduledFuture<?> timeout;
private volatile long lastReadTime;
private volatile boolean destroyed;
private volatile int state; // 0 - none, 1 - Initialized, 2 - Destroyed;
private boolean closed;
@ -110,12 +110,12 @@ public class ReadTimeoutHandler extends ChannelStateHandlerAdapter {
@Override
public void beforeAdd(ChannelHandlerContext ctx) throws Exception {
if (ctx.channel().isActive()) {
if (ctx.channel().isActive() && ctx.channel().isRegistered()) {
// channelActvie() event has been fired already, which means this.channelActive() will
// not be invoked. We have to initialize here instead.
initialize(ctx);
} else {
// channelActive() event has not been fired yet. this.channelOpen() will be invoked
// channelActive() event has not been fired yet. this.channelActive() will be invoked
// and initialization will occur there.
}
}
@ -126,8 +126,16 @@ public class ReadTimeoutHandler extends ChannelStateHandlerAdapter {
}
@Override
public void channelActive(ChannelHandlerContext ctx)
throws Exception {
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
// Initialize early if channel is active already.
if (ctx.channel().isActive()) {
initialize(ctx);
}
super.channelRegistered(ctx);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// This method will be invoked only if this handler was added
// before channelActive() event is fired. If a user adds this handler
// after the channelActive() event, initialize() will be called by beforeAdd().
@ -150,10 +158,14 @@ public class ReadTimeoutHandler extends ChannelStateHandlerAdapter {
private void initialize(ChannelHandlerContext ctx) {
// Avoid the case where destroy() is called before scheduling timeouts.
// See: https://github.com/netty/netty/issues/143
if (destroyed) {
switch (state) {
case 1:
case 2:
return;
}
state = 1;
lastReadTime = System.currentTimeMillis();
if (timeoutMillis > 0) {
timeout = ctx.executor().schedule(
@ -163,7 +175,7 @@ public class ReadTimeoutHandler extends ChannelStateHandlerAdapter {
}
private void destroy() {
destroyed = true;
state = 2;
if (timeout != null) {
timeout.cancel(false);