NioEventLoop#rebuildSelector0 throws ClassCastException
Motivation:
Commit 795f318
simplified some code related to the special case Set for the selected keys and introduced a Selector wrapper to make sure this set was properly reset. However the JDK makes assumptions about the type of Selector and this type is not extensible. This means whenever we call into the JDK we must provide the unwrapped version of the Selector or we get a ClassCastException. We missed a case of unwrapping in NioEventLoop#rebuildSelector0.
Modificaitons:
- NioEventLoop#openSelector should return a tuple so we can atomically set the wrapped and unwrapped Selector
- NioEventLoop#rebuildSelector0 should use the unwrapped version of the selector
Result:
Fixes https://github.com/netty/netty/issues/6607.
This commit is contained in:
parent
077a1988b9
commit
c37267d682
@ -146,11 +146,29 @@ public final class NioEventLoop extends SingleThreadEventLoop {
|
||||
throw new NullPointerException("selectStrategy");
|
||||
}
|
||||
provider = selectorProvider;
|
||||
selector = openSelector();
|
||||
final SelectorTuple selectorTuple = openSelector();
|
||||
selector = selectorTuple.selector;
|
||||
unwrappedSelector = selectorTuple.unwrappedSelector;
|
||||
selectStrategy = strategy;
|
||||
}
|
||||
|
||||
private Selector openSelector() {
|
||||
private static final class SelectorTuple {
|
||||
final Selector unwrappedSelector;
|
||||
final Selector selector;
|
||||
|
||||
SelectorTuple(Selector unwrappedSelector) {
|
||||
this.unwrappedSelector = unwrappedSelector;
|
||||
this.selector = unwrappedSelector;
|
||||
}
|
||||
|
||||
SelectorTuple(Selector unwrappedSelector, Selector selector) {
|
||||
this.unwrappedSelector = unwrappedSelector;
|
||||
this.selector = selector;
|
||||
}
|
||||
}
|
||||
|
||||
private SelectorTuple openSelector() {
|
||||
final Selector unwrappedSelector;
|
||||
try {
|
||||
unwrappedSelector = provider.openSelector();
|
||||
} catch (IOException e) {
|
||||
@ -158,7 +176,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
|
||||
}
|
||||
|
||||
if (DISABLE_KEYSET_OPTIMIZATION) {
|
||||
return unwrappedSelector;
|
||||
return new SelectorTuple(unwrappedSelector);
|
||||
}
|
||||
|
||||
final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
|
||||
@ -184,7 +202,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
|
||||
Throwable t = (Throwable) maybeSelectorImplClass;
|
||||
logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, t);
|
||||
}
|
||||
return unwrappedSelector;
|
||||
return new SelectorTuple(unwrappedSelector);
|
||||
}
|
||||
|
||||
final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass;
|
||||
@ -220,11 +238,12 @@ public final class NioEventLoop extends SingleThreadEventLoop {
|
||||
selectedKeys = null;
|
||||
Exception e = (Exception) maybeException;
|
||||
logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, e);
|
||||
return unwrappedSelector;
|
||||
return new SelectorTuple(unwrappedSelector);
|
||||
}
|
||||
selectedKeys = selectedKeySet;
|
||||
logger.trace("instrumented a special java.util.Set into: {}", unwrappedSelector);
|
||||
return new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet);
|
||||
return new SelectorTuple(unwrappedSelector,
|
||||
new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -320,14 +339,14 @@ public final class NioEventLoop extends SingleThreadEventLoop {
|
||||
|
||||
private void rebuildSelector0() {
|
||||
final Selector oldSelector = selector;
|
||||
final Selector newSelector;
|
||||
final SelectorTuple newSelectorTuple;
|
||||
|
||||
if (oldSelector == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
newSelector = openSelector();
|
||||
newSelectorTuple = openSelector();
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to create a new Selector.", e);
|
||||
return;
|
||||
@ -338,13 +357,13 @@ public final class NioEventLoop extends SingleThreadEventLoop {
|
||||
for (SelectionKey key: oldSelector.keys()) {
|
||||
Object a = key.attachment();
|
||||
try {
|
||||
if (!key.isValid() || key.channel().keyFor(newSelector) != null) {
|
||||
if (!key.isValid() || key.channel().keyFor(newSelectorTuple.unwrappedSelector) != null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int interestOps = key.interestOps();
|
||||
key.cancel();
|
||||
SelectionKey newKey = key.channel().register(newSelector, interestOps, a);
|
||||
SelectionKey newKey = key.channel().register(newSelectorTuple.unwrappedSelector, interestOps, a);
|
||||
if (a instanceof AbstractNioChannel) {
|
||||
// Update SelectionKey
|
||||
((AbstractNioChannel) a).selectionKey = newKey;
|
||||
@ -363,7 +382,8 @@ public final class NioEventLoop extends SingleThreadEventLoop {
|
||||
}
|
||||
}
|
||||
|
||||
selector = newSelector;
|
||||
selector = newSelectorTuple.selector;
|
||||
unwrappedSelector = newSelectorTuple.unwrappedSelector;
|
||||
|
||||
try {
|
||||
// time to close the old selector as everything else is registered to the new one
|
||||
|
Loading…
Reference in New Issue
Block a user