Revert 25c7a783a7
and fix #1064 differently
- Rename inbound/outboundBufferFreed to inbound/OutboundShutdown which makes more sense - Move DefaultChannelHandlerContext.isInbound/OutboundBufferFreed() to DefaultChannelPipeline - Fix a problem where invokeFreeInbound/OutboundBuffer() sets inbound/outboundShutdown too early (this was the direct cause of #1064) - Remove the volatile modifier - DCHC.prev/next are volatile and that's just enough
This commit is contained in:
parent
a9a8d5d8c2
commit
0f46d4b379
@ -740,7 +740,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
||||
public ChannelHandlerContext fireChannelUnregistered() {
|
||||
final DefaultChannelHandlerContext next = findContextInbound();
|
||||
EventExecutor executor = next.executor();
|
||||
if (executor.inEventLoop()) {
|
||||
if (prev != null && executor.inEventLoop()) {
|
||||
next.invokeChannelUnregistered();
|
||||
} else {
|
||||
Runnable task = next.invokeChannelUnregisteredTask;
|
||||
@ -749,6 +749,9 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
||||
@Override
|
||||
public void run() {
|
||||
next.invokeChannelUnregistered();
|
||||
if (prev == null) {
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -801,7 +804,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
||||
public ChannelHandlerContext fireChannelInactive() {
|
||||
final DefaultChannelHandlerContext next = findContextInbound();
|
||||
EventExecutor executor = next.executor();
|
||||
if (executor.inEventLoop()) {
|
||||
if (prev != null && executor.inEventLoop()) {
|
||||
next.invokeChannelInactive();
|
||||
} else {
|
||||
Runnable task = next.invokeChannelInactiveTask;
|
||||
@ -836,7 +839,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
||||
|
||||
final DefaultChannelHandlerContext next = this.next;
|
||||
EventExecutor executor = next.executor();
|
||||
if (executor.inEventLoop()) {
|
||||
if (prev != null && executor.inEventLoop()) {
|
||||
next.invokeExceptionCaught(cause);
|
||||
} else {
|
||||
try {
|
||||
@ -923,7 +926,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
||||
|
||||
private void fireInboundBufferUpdated0() {
|
||||
final DefaultChannelHandlerContext next = findContextInbound();
|
||||
if (!next.isInboundBufferFreed()) {
|
||||
if (!pipeline.isInboundShutdown()) {
|
||||
next.fillInboundBridge();
|
||||
// This comparison is safe because this method is always executed from the executor.
|
||||
if (next.executor == executor) {
|
||||
@ -934,7 +937,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
||||
next.invokeInboundBufferUpdatedTask = task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!next.isInboundBufferFreed()) {
|
||||
if (!pipeline.isInboundShutdown()) {
|
||||
next.invokeInboundBufferUpdated();
|
||||
}
|
||||
}
|
||||
@ -959,7 +962,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
||||
} catch (Throwable t) {
|
||||
pipeline.notifyHandlerException(t);
|
||||
} finally {
|
||||
if (handler instanceof ChannelInboundByteHandler && !isInboundBufferFreed()) {
|
||||
if (handler instanceof ChannelInboundByteHandler && !pipeline.isInboundShutdown()) {
|
||||
try {
|
||||
((ChannelInboundByteHandler) handler).discardInboundReadBytes(this);
|
||||
} catch (Throwable t) {
|
||||
@ -1282,7 +1285,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
||||
|
||||
private void invokePrevFlush(ChannelPromise promise, Thread currentThread) {
|
||||
DefaultChannelHandlerContext prev = findContextOutbound();
|
||||
if (prev.isOutboundBufferFreed()) {
|
||||
if (pipeline.isOutboundShutdown()) {
|
||||
promise.setFailure(new ChannelPipelineException(
|
||||
"Unable to flush as outbound buffer of next handler was freed already"));
|
||||
return;
|
||||
@ -1324,7 +1327,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
||||
} catch (Throwable t) {
|
||||
pipeline.notifyHandlerException(t);
|
||||
} finally {
|
||||
if (handler instanceof ChannelOutboundByteHandler && !isOutboundBufferFreed()) {
|
||||
if (handler instanceof ChannelOutboundByteHandler && !pipeline.isOutboundShutdown()) {
|
||||
try {
|
||||
((ChannelOutboundByteHandler) handler).discardOutboundReadBytes(this);
|
||||
} catch (Throwable t) {
|
||||
@ -1446,7 +1449,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
||||
return;
|
||||
}
|
||||
|
||||
if (isOutboundBufferFreed()) {
|
||||
if (pipeline.isOutboundShutdown()) {
|
||||
promise.setFailure(new ChannelPipelineException(
|
||||
"Unable to write as outbound buffer of next handler was freed already"));
|
||||
return;
|
||||
@ -1461,9 +1464,8 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
||||
}
|
||||
|
||||
void invokeFreeInboundBuffer() {
|
||||
pipeline.inboundBufferFreed = true;
|
||||
EventExecutor executor = executor();
|
||||
if (executor.inEventLoop()) {
|
||||
if (prev != null && executor.inEventLoop()) {
|
||||
invokeFreeInboundBuffer0();
|
||||
} else {
|
||||
Runnable task = invokeFreeInboundBuffer0Task;
|
||||
@ -1471,6 +1473,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
||||
invokeFreeInboundBuffer0Task = task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
pipeline.shutdownInbound();
|
||||
invokeFreeInboundBuffer0();
|
||||
}
|
||||
};
|
||||
@ -1503,21 +1506,39 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
||||
|
||||
/** Invocation initiated by {@link #invokeFreeInboundBuffer0()} after freeing all inbound buffers. */
|
||||
private void invokeFreeOutboundBuffer() {
|
||||
pipeline.outboundBufferFreed = true;
|
||||
EventExecutor executor = executor();
|
||||
if (executor.inEventLoop()) {
|
||||
invokeFreeOutboundBuffer0();
|
||||
} else {
|
||||
Runnable task = invokeFreeOutboundBuffer0Task;
|
||||
if (task == null) {
|
||||
invokeFreeOutboundBuffer0Task = task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
invokeFreeOutboundBuffer0();
|
||||
}
|
||||
};
|
||||
if (next == null) {
|
||||
if (executor.inEventLoop()) {
|
||||
pipeline.shutdownOutbound();
|
||||
invokeFreeOutboundBuffer0();
|
||||
} else {
|
||||
Runnable task = invokeFreeOutboundBuffer0Task;
|
||||
if (task == null) {
|
||||
invokeFreeOutboundBuffer0Task = task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
pipeline.shutdownOutbound();
|
||||
invokeFreeOutboundBuffer0();
|
||||
}
|
||||
};
|
||||
}
|
||||
executor.execute(task);
|
||||
}
|
||||
} else {
|
||||
if (executor.inEventLoop()) {
|
||||
invokeFreeOutboundBuffer0();
|
||||
} else {
|
||||
Runnable task = invokeFreeOutboundBuffer0Task;
|
||||
if (task == null) {
|
||||
invokeFreeOutboundBuffer0Task = task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
invokeFreeOutboundBuffer0();
|
||||
}
|
||||
};
|
||||
}
|
||||
executor.execute(task);
|
||||
}
|
||||
executor.execute(task);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1569,14 +1590,6 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInboundBufferFreed() {
|
||||
return pipeline.inboundBufferFreed;
|
||||
}
|
||||
|
||||
private boolean isOutboundBufferFreed() {
|
||||
return pipeline.outboundBufferFreed;
|
||||
}
|
||||
|
||||
private void validateFuture(ChannelFuture future) {
|
||||
if (future == null) {
|
||||
throw new NullPointerException("future");
|
||||
|
@ -58,8 +58,8 @@ final class DefaultChannelPipeline implements ChannelPipeline {
|
||||
final Map<EventExecutorGroup, EventExecutor> childExecutors =
|
||||
new IdentityHashMap<EventExecutorGroup, EventExecutor>();
|
||||
|
||||
volatile boolean inboundBufferFreed;
|
||||
volatile boolean outboundBufferFreed;
|
||||
private boolean inboundShutdown;
|
||||
private boolean outboundShutdown;
|
||||
|
||||
public DefaultChannelPipeline(Channel channel) {
|
||||
if (channel == null) {
|
||||
@ -845,6 +845,22 @@ final class DefaultChannelPipeline implements ChannelPipeline {
|
||||
return tail.nextOutboundByteBuffer();
|
||||
}
|
||||
|
||||
boolean isInboundShutdown() {
|
||||
return inboundShutdown;
|
||||
}
|
||||
|
||||
boolean isOutboundShutdown() {
|
||||
return outboundShutdown;
|
||||
}
|
||||
|
||||
void shutdownInbound() {
|
||||
inboundShutdown = true;
|
||||
}
|
||||
|
||||
void shutdownOutbound() {
|
||||
outboundShutdown = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelPipeline fireChannelRegistered() {
|
||||
head.fireChannelRegistered();
|
||||
|
Loading…
Reference in New Issue
Block a user