diff --git a/common/src/main/java/io/netty/util/internal/PlatformDependent.java b/common/src/main/java/io/netty/util/internal/PlatformDependent.java index 870f80959f..8fc7f5f07d 100644 --- a/common/src/main/java/io/netty/util/internal/PlatformDependent.java +++ b/common/src/main/java/io/netty/util/internal/PlatformDependent.java @@ -246,6 +246,13 @@ public final class PlatformDependent { return HAS_UNSAFE; } + /** + * Return the reason (if any) why {@code sun.misc.Unsafe} was not available. + */ + public static Throwable getUnsafeUnavailabilityCause() { + return PlatformDependent0.getUnsafeUnavailabilityCause(); + } + /** * {@code true} if and only if the platform supports unaligned access. * @@ -966,7 +973,8 @@ public final class PlatformDependent { boolean hasUnsafe = PlatformDependent0.hasUnsafe(); logger.debug("sun.misc.Unsafe: {}", hasUnsafe ? "available" : "unavailable"); return hasUnsafe; - } catch (Throwable ignored) { + } catch (Throwable t) { + logger.trace("Could not determine if Unsafe is available", t); // Probably failed to initialize PlatformDependent0. return false; } diff --git a/common/src/main/java/io/netty/util/internal/PlatformDependent0.java b/common/src/main/java/io/netty/util/internal/PlatformDependent0.java index 1464092b25..3c8de0e7a5 100644 --- a/common/src/main/java/io/netty/util/internal/PlatformDependent0.java +++ b/common/src/main/java/io/netty/util/internal/PlatformDependent0.java @@ -44,6 +44,7 @@ final class PlatformDependent0 { private static final int JAVA_VERSION = javaVersion0(); private static final boolean IS_ANDROID = isAndroid0(); + private static final Throwable UNSAFE_UNAVAILABILITY_CAUSE; private static final Object INTERNAL_UNSAFE; static final Unsafe UNSAFE; @@ -64,12 +65,14 @@ final class PlatformDependent0 { final ByteBuffer direct; Field addressField = null; Method allocateArrayMethod = null; + Throwable unsafeUnavailabilityCause = null; Unsafe unsafe; Object internalUnsafe = null; if (isExplicitNoUnsafe()) { direct = null; addressField = null; + unsafeUnavailabilityCause = new UnsupportedOperationException("Unsafe explicitly disabled"); unsafe = null; internalUnsafe = null; } else { @@ -101,9 +104,10 @@ final class PlatformDependent0 { // is an instanceof Unsafe and reversing the if and else blocks; this is because an // instanceof check against Unsafe will trigger a class load and we might not have // the runtime permission accessClassInPackage.sun.misc - if (maybeUnsafe instanceof Exception) { + if (maybeUnsafe instanceof Throwable) { unsafe = null; - logger.debug("sun.misc.Unsafe.theUnsafe: unavailable", (Exception) maybeUnsafe); + unsafeUnavailabilityCause = (Throwable) maybeUnsafe; + logger.debug("sun.misc.Unsafe.theUnsafe: unavailable", (Throwable) maybeUnsafe); } else { unsafe = (Unsafe) maybeUnsafe; logger.debug("sun.misc.Unsafe.theUnsafe: available"); @@ -134,6 +138,7 @@ final class PlatformDependent0 { } else { // Unsafe.copyMemory(Object, long, Object, long, long) unavailable. unsafe = null; + unsafeUnavailabilityCause = (Throwable) maybeException; logger.debug("sun.misc.Unsafe.copyMemory: unavailable", (Throwable) maybeException); } } @@ -169,6 +174,7 @@ final class PlatformDependent0 { addressField = (Field) maybeAddressField; logger.debug("java.nio.Buffer.address: available"); } else { + unsafeUnavailabilityCause = (Throwable) maybeAddressField; logger.debug("java.nio.Buffer.address: unavailable", (Throwable) maybeAddressField); // If we cannot access the address of a direct buffer, there's no point of using unsafe. @@ -183,10 +189,12 @@ final class PlatformDependent0 { long byteArrayIndexScale = unsafe.arrayIndexScale(byte[].class); if (byteArrayIndexScale != 1) { logger.debug("unsafe.arrayIndexScale is {} (expected: 1). Not using unsafe.", byteArrayIndexScale); + unsafeUnavailabilityCause = new UnsupportedOperationException("Unexpected unsafe.arrayIndexScale"); unsafe = null; } } } + UNSAFE_UNAVAILABILITY_CAUSE = unsafeUnavailabilityCause; UNSAFE = unsafe; if (unsafe == null) { @@ -389,6 +397,10 @@ final class PlatformDependent0 { return UNSAFE != null; } + static Throwable getUnsafeUnavailabilityCause() { + return UNSAFE_UNAVAILABILITY_CAUSE; + } + static boolean unalignedAccess() { return UNALIGNED; } diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/Epoll.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/Epoll.java index 0ec4fd99f5..2f06f5bbc4 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/Epoll.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/Epoll.java @@ -54,8 +54,11 @@ public final class Epoll { if (cause != null) { UNAVAILABILITY_CAUSE = cause; } else { - UNAVAILABILITY_CAUSE = PlatformDependent.hasUnsafe() ? null : - new IllegalStateException("sun.misc.Unsafe not available"); + UNAVAILABILITY_CAUSE = PlatformDependent.hasUnsafe() + ? null + : new IllegalStateException( + "sun.misc.Unsafe not available", + PlatformDependent.getUnsafeUnavailabilityCause()); } } diff --git a/transport-native-kqueue/src/main/java/io/netty/channel/kqueue/KQueue.java b/transport-native-kqueue/src/main/java/io/netty/channel/kqueue/KQueue.java index 3377d9fdac..a0b3ac6fce 100644 --- a/transport-native-kqueue/src/main/java/io/netty/channel/kqueue/KQueue.java +++ b/transport-native-kqueue/src/main/java/io/netty/channel/kqueue/KQueue.java @@ -46,8 +46,11 @@ public final class KQueue { if (cause != null) { UNAVAILABILITY_CAUSE = cause; } else { - UNAVAILABILITY_CAUSE = PlatformDependent.hasUnsafe() ? null : - new IllegalStateException("sun.misc.Unsafe not available"); + UNAVAILABILITY_CAUSE = PlatformDependent.hasUnsafe() + ? null + : new IllegalStateException( + "sun.misc.Unsafe not available", + PlatformDependent.getUnsafeUnavailabilityCause()); } }