Make sure ChannelFutureListeners are invoked from an event loop thread
This commit is contained in:
parent
0682421ce1
commit
a83b9704fa
@ -15,11 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.channel;
|
package io.netty.channel;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import io.netty.logging.InternalLogger;
|
import io.netty.logging.InternalLogger;
|
||||||
import io.netty.logging.InternalLoggerFactory;
|
import io.netty.logging.InternalLoggerFactory;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A skeletal {@link ChannelFuture} implementation which represents a
|
* A skeletal {@link ChannelFuture} implementation which represents a
|
||||||
* {@link ChannelFuture} which has been completed already.
|
* {@link ChannelFuture} which has been completed already.
|
||||||
@ -44,7 +44,20 @@ public abstract class CompleteChannelFuture implements ChannelFuture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addListener(ChannelFutureListener listener) {
|
public void addListener(final ChannelFutureListener listener) {
|
||||||
|
if (channel().eventLoop().inEventLoop()) {
|
||||||
|
notifyListener(listener);
|
||||||
|
} else {
|
||||||
|
channel().eventLoop().execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
notifyListener(listener);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyListener(ChannelFutureListener listener) {
|
||||||
try {
|
try {
|
||||||
listener.operationComplete(this);
|
listener.operationComplete(this);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
@ -16,16 +16,16 @@
|
|||||||
package io.netty.channel;
|
package io.netty.channel;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.*;
|
import static java.util.concurrent.TimeUnit.*;
|
||||||
|
import io.netty.logging.InternalLogger;
|
||||||
|
import io.netty.logging.InternalLoggerFactory;
|
||||||
|
import io.netty.util.internal.DeadLockProofWorker;
|
||||||
|
|
||||||
|
import java.nio.channels.Channels;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import io.netty.logging.InternalLogger;
|
|
||||||
import io.netty.logging.InternalLoggerFactory;
|
|
||||||
import io.netty.util.internal.DeadLockProofWorker;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default {@link ChannelFuture} implementation. It is recommended to
|
* The default {@link ChannelFuture} implementation. It is recommended to
|
||||||
* use {@link Channels#future(Channel)} and {@link Channels#future(Channel, boolean)}
|
* use {@link Channels#future(Channel)} and {@link Channels#future(Channel, boolean)}
|
||||||
@ -119,7 +119,7 @@ public class DefaultChannelFuture implements ChannelFuture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addListener(ChannelFutureListener listener) {
|
public void addListener(final ChannelFutureListener listener) {
|
||||||
if (listener == null) {
|
if (listener == null) {
|
||||||
throw new NullPointerException("listener");
|
throw new NullPointerException("listener");
|
||||||
}
|
}
|
||||||
@ -148,7 +148,17 @@ public class DefaultChannelFuture implements ChannelFuture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (notifyNow) {
|
if (notifyNow) {
|
||||||
notifyListener(listener);
|
if (channel().eventLoop().inEventLoop()) {
|
||||||
|
notifyListener(listener);
|
||||||
|
} else {
|
||||||
|
channel().eventLoop().execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
notifyListener(listener);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +192,7 @@ public class DefaultChannelFuture implements ChannelFuture {
|
|||||||
if (!isDone()) {
|
if (!isDone()) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Throwable cause = cause();
|
Throwable cause = cause();
|
||||||
if (cause == null) {
|
if (cause == null) {
|
||||||
return this;
|
return this;
|
||||||
@ -398,7 +408,12 @@ public class DefaultChannelFuture implements ChannelFuture {
|
|||||||
// Hence any listener list modification happens-before this method.
|
// Hence any listener list modification happens-before this method.
|
||||||
// 2) This method is called only when 'done' is true. Once 'done'
|
// 2) This method is called only when 'done' is true. Once 'done'
|
||||||
// becomes true, the listener list is never modified - see add/removeListener()
|
// becomes true, the listener list is never modified - see add/removeListener()
|
||||||
if (firstListener != null) {
|
|
||||||
|
if (firstListener == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel().eventLoop().inEventLoop()) {
|
||||||
notifyListener(firstListener);
|
notifyListener(firstListener);
|
||||||
firstListener = null;
|
firstListener = null;
|
||||||
|
|
||||||
@ -408,6 +423,22 @@ public class DefaultChannelFuture implements ChannelFuture {
|
|||||||
}
|
}
|
||||||
otherListeners = null;
|
otherListeners = null;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
final ChannelFutureListener firstListener = this.firstListener;
|
||||||
|
final List<ChannelFutureListener> otherListeners = this.otherListeners;
|
||||||
|
this.firstListener = null;
|
||||||
|
this.otherListeners = null;
|
||||||
|
channel().eventLoop().execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
notifyListener(firstListener);
|
||||||
|
if (otherListeners != null) {
|
||||||
|
for (ChannelFutureListener l: otherListeners) {
|
||||||
|
notifyListener(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user