Correctly detect if the Selector.select(..) unblocks because of a manual wakup or because of a closed channel. See #327

This commit is contained in:
Norman Maurer 2012-08-31 02:23:31 +02:00
parent 883af62c92
commit 63a234ba12

View File

@ -21,10 +21,12 @@ import java.io.IOException;
import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.DatagramChannel;
import java.nio.channels.NotYetConnectedException;
import java.nio.channels.SocketChannel;
import java.nio.channels.SelectableChannel;
import java.nio.channels.Selector;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.WritableByteChannel;
import java.util.Iterator;
@ -248,8 +250,8 @@ abstract class AbstractNioWorker implements Worker {
Selector selector = this.selector;
// use 80% of the timeout for measure
long minSelectTimeout = SelectorUtil.SELECT_TIMEOUT_NANOS / 100 * 80;
long minSelectTimeout = (long) (SelectorUtil.SELECT_TIMEOUT_NANOS * 0.8);
boolean wakupFromLoop = false;
for (;;) {
wakenUp.set(false);
@ -263,23 +265,42 @@ abstract class AbstractNioWorker implements Worker {
try {
long beforeSelect = System.nanoTime();
int selected = SelectorUtil.select(selector);
if (selected == 0) {
long timeBlocked = System.nanoTime() - beforeSelect;
if (selected == 0 && !wakupFromLoop && !wakenUp.get()) {
long timeBlocked = System.nanoTime() - beforeSelect;
if (timeBlocked < minSelectTimeout) {
// returned before the minSelectTimeout elapsed with nothing select.
// this may be the cause of the jdk epoll(..) bug, so increment the counter
// which we use later to see if its really the jdk bug.
selectReturnsImmediately ++;
boolean notConnected = false;
// loop over all keys as the selector may was unblocked because of a closed channel
for (SelectionKey key: selector.keys()) {
SelectableChannel ch = key.channel();
if ((ch instanceof DatagramChannel && !((DatagramChannel) ch).isConnected()) ||
ch instanceof SocketChannel && !((SocketChannel) ch).isConnected()) {
notConnected = true;
// cancel the key just to be on the safe side
key.cancel();
}
}
if (notConnected) {
selectReturnsImmediately = 0;
} else {
// returned before the minSelectTimeout elapsed with nothing select.
// this may be the cause of the jdk epoll(..) bug, so increment the counter
// which we use later to see if its really the jdk bug.
selectReturnsImmediately ++;
}
} else {
selectReturnsImmediately = 0;
}
if (selectReturnsImmediately == 10) {
if (selectReturnsImmediately == 50) {
// The selector returned immediately for 10 times in a row,
// so recreate one selector as it seems like we hit the
// famous epoll(..) jdk bug.
selector = recreateSelector();
selectReturnsImmediately = 0;
wakupFromLoop = false;
// try to select again
continue;
}
@ -317,7 +338,10 @@ abstract class AbstractNioWorker implements Worker {
// (OK - no wake-up required).
if (wakenUp.get()) {
wakupFromLoop = true;
selector.wakeup();
} else {
wakupFromLoop = false;
}
cancelledKeys = 0;