more work on nio event loop

This commit is contained in:
Jörg Prante 2023-09-22 16:27:40 +02:00
parent 73188102fe
commit 98d0a34c88

View file

@ -8,6 +8,7 @@ import org.xbib.event.loop.SingleThreadEventLoop;
import org.xbib.event.util.IntSupplier;
import java.io.IOException;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.SelectableChannel;
@ -15,14 +16,8 @@ import java.nio.channels.Selector;
import java.nio.channels.SelectionKey;
import java.nio.channels.spi.SelectorProvider;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Objects;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
@ -155,8 +150,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
}
// ensure the current selector implementation is what we can instrument.
if (maybeSelectorImplClass == null ||
!maybeSelectorImplClass.isAssignableFrom(unwrappedSelector.getClass())) {
if (maybeSelectorImplClass == null || !maybeSelectorImplClass.isAssignableFrom(unwrappedSelector.getClass())) {
return new SelectorTuple(unwrappedSelector);
}
@ -167,40 +161,19 @@ public final class NioEventLoop extends SingleThreadEventLoop {
try {
Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
if (PlatformDependent.javaVersion() >= 9 && PlatformDependent.hasUnsafe()) {
// Let us try to use sun.misc.Unsafe to replace the SelectionKeySet.
// This allows us to also do this in Java9+ without any extra flags.
long selectedKeysFieldOffset = PlatformDependent.objectFieldOffset(selectedKeysField);
long publicSelectedKeysFieldOffset =
PlatformDependent.objectFieldOffset(publicSelectedKeysField);
if (selectedKeysFieldOffset != -1 && publicSelectedKeysFieldOffset != -1) {
PlatformDependent.putObject(
unwrappedSelector, selectedKeysFieldOffset, selectedKeySet);
PlatformDependent.putObject(
unwrappedSelector, publicSelectedKeysFieldOffset, selectedKeySet);
return null;
}
// We could not retrieve the offset, lets try reflection as last-resort.
}
Throwable cause = ReflectionUtil.trySetAccessible(selectedKeysField, true);
Throwable cause = trySetAccessible(selectedKeysField, true);
if (cause != null) {
return cause;
maybeException = cause;
}
cause = ReflectionUtil.trySetAccessible(publicSelectedKeysField, true);
cause = trySetAccessible(publicSelectedKeysField, true);
if (cause != null) {
return cause;
maybeException = cause;
}
selectedKeysField.set(unwrappedSelector, selectedKeySet);
publicSelectedKeysField.set(unwrappedSelector, selectedKeySet);
return null;
} catch (NoSuchFieldException | IllegalAccessException e) {
maybeException = e;
}
if (maybeException instanceof Exception) {
selectedKeys = null;
Exception e = (Exception) maybeException;
@ -763,4 +736,40 @@ public final class NioEventLoop extends SingleThreadEventLoop {
logger.log(Level.WARNING, "Failed to update SelectionKeys.", t);
}
}
private static Throwable trySetAccessible(AccessibleObject object, boolean checkAccessible) {
if (checkAccessible && !isExplicitTryReflectionSetAccessible()) {
return new UnsupportedOperationException("Reflective setAccessible(true) disabled");
}
try {
object.setAccessible(true);
return null;
} catch (SecurityException e) {
return e;
}
}
private static boolean isExplicitTryReflectionSetAccessible() {
// we disable reflective access
boolean defaultValue = javaVersion() < 9 || System.getProperties().containsKey("org.graalvm.nativeimage.imagecode");
return Boolean.parseBoolean(System.getProperties().getProperty("io.netty.tryReflectionSetAccessible",
Boolean.toString(defaultValue)));
}
private static int javaVersion() {
return majorVersion(System.getProperties().getProperty("java.specification.version", "1.6"));
}
private static int majorVersion(String javaSpecVersion) {
final String[] components = javaSpecVersion.split("\\.");
final int[] version = new int[components.length];
for (int i = 0; i < components.length; i++) {
version[i] = Integer.parseInt(components[i]);
}
if (version[0] == 1) {
assert version[1] >= 6;
return version[1];
} else {
return version[0];
}
}
}