Include more detail why Unsafe is not available

Motivation:
PD and PD0 Both try to find and use Unsafe.  If unavailable, they
try to log why and continue on.  However, it is not always east to
enable this logging.  Chaining exceptions together is much easier
to reach, and the original exception is relevant when Unsafe is
needed.

Modifications:
* Make PD log why PD0 could not be loaded with a trace level log
* Make PD0 remember why Unsafe wasn't available
* Expose unavailability cause through PD for higher level use.
* Make Epoll and KQueue include the reason when failing

Result:
Easier debugging in hard to reconfigure environments
This commit is contained in:
Carl Mastrangelo 2017-08-23 19:31:09 -07:00 committed by Norman Maurer
parent f5bea11ee4
commit c891c9c13f
4 changed files with 33 additions and 7 deletions

View File

@ -246,6 +246,13 @@ public final class PlatformDependent {
return HAS_UNSAFE; 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. * {@code true} if and only if the platform supports unaligned access.
* *
@ -966,7 +973,8 @@ public final class PlatformDependent {
boolean hasUnsafe = PlatformDependent0.hasUnsafe(); boolean hasUnsafe = PlatformDependent0.hasUnsafe();
logger.debug("sun.misc.Unsafe: {}", hasUnsafe ? "available" : "unavailable"); logger.debug("sun.misc.Unsafe: {}", hasUnsafe ? "available" : "unavailable");
return hasUnsafe; return hasUnsafe;
} catch (Throwable ignored) { } catch (Throwable t) {
logger.trace("Could not determine if Unsafe is available", t);
// Probably failed to initialize PlatformDependent0. // Probably failed to initialize PlatformDependent0.
return false; return false;
} }

View File

@ -44,6 +44,7 @@ final class PlatformDependent0 {
private static final int JAVA_VERSION = javaVersion0(); private static final int JAVA_VERSION = javaVersion0();
private static final boolean IS_ANDROID = isAndroid0(); private static final boolean IS_ANDROID = isAndroid0();
private static final Throwable UNSAFE_UNAVAILABILITY_CAUSE;
private static final Object INTERNAL_UNSAFE; private static final Object INTERNAL_UNSAFE;
static final Unsafe UNSAFE; static final Unsafe UNSAFE;
@ -64,12 +65,14 @@ final class PlatformDependent0 {
final ByteBuffer direct; final ByteBuffer direct;
Field addressField = null; Field addressField = null;
Method allocateArrayMethod = null; Method allocateArrayMethod = null;
Throwable unsafeUnavailabilityCause = null;
Unsafe unsafe; Unsafe unsafe;
Object internalUnsafe = null; Object internalUnsafe = null;
if (isExplicitNoUnsafe()) { if (isExplicitNoUnsafe()) {
direct = null; direct = null;
addressField = null; addressField = null;
unsafeUnavailabilityCause = new UnsupportedOperationException("Unsafe explicitly disabled");
unsafe = null; unsafe = null;
internalUnsafe = null; internalUnsafe = null;
} else { } else {
@ -101,9 +104,10 @@ final class PlatformDependent0 {
// is an instanceof Unsafe and reversing the if and else blocks; this is because an // 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 // instanceof check against Unsafe will trigger a class load and we might not have
// the runtime permission accessClassInPackage.sun.misc // the runtime permission accessClassInPackage.sun.misc
if (maybeUnsafe instanceof Exception) { if (maybeUnsafe instanceof Throwable) {
unsafe = null; unsafe = null;
logger.debug("sun.misc.Unsafe.theUnsafe: unavailable", (Exception) maybeUnsafe); unsafeUnavailabilityCause = (Throwable) maybeUnsafe;
logger.debug("sun.misc.Unsafe.theUnsafe: unavailable", (Throwable) maybeUnsafe);
} else { } else {
unsafe = (Unsafe) maybeUnsafe; unsafe = (Unsafe) maybeUnsafe;
logger.debug("sun.misc.Unsafe.theUnsafe: available"); logger.debug("sun.misc.Unsafe.theUnsafe: available");
@ -134,6 +138,7 @@ final class PlatformDependent0 {
} else { } else {
// Unsafe.copyMemory(Object, long, Object, long, long) unavailable. // Unsafe.copyMemory(Object, long, Object, long, long) unavailable.
unsafe = null; unsafe = null;
unsafeUnavailabilityCause = (Throwable) maybeException;
logger.debug("sun.misc.Unsafe.copyMemory: unavailable", (Throwable) maybeException); logger.debug("sun.misc.Unsafe.copyMemory: unavailable", (Throwable) maybeException);
} }
} }
@ -169,6 +174,7 @@ final class PlatformDependent0 {
addressField = (Field) maybeAddressField; addressField = (Field) maybeAddressField;
logger.debug("java.nio.Buffer.address: available"); logger.debug("java.nio.Buffer.address: available");
} else { } else {
unsafeUnavailabilityCause = (Throwable) maybeAddressField;
logger.debug("java.nio.Buffer.address: unavailable", (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. // 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); long byteArrayIndexScale = unsafe.arrayIndexScale(byte[].class);
if (byteArrayIndexScale != 1) { if (byteArrayIndexScale != 1) {
logger.debug("unsafe.arrayIndexScale is {} (expected: 1). Not using unsafe.", byteArrayIndexScale); logger.debug("unsafe.arrayIndexScale is {} (expected: 1). Not using unsafe.", byteArrayIndexScale);
unsafeUnavailabilityCause = new UnsupportedOperationException("Unexpected unsafe.arrayIndexScale");
unsafe = null; unsafe = null;
} }
} }
} }
UNSAFE_UNAVAILABILITY_CAUSE = unsafeUnavailabilityCause;
UNSAFE = unsafe; UNSAFE = unsafe;
if (unsafe == null) { if (unsafe == null) {
@ -389,6 +397,10 @@ final class PlatformDependent0 {
return UNSAFE != null; return UNSAFE != null;
} }
static Throwable getUnsafeUnavailabilityCause() {
return UNSAFE_UNAVAILABILITY_CAUSE;
}
static boolean unalignedAccess() { static boolean unalignedAccess() {
return UNALIGNED; return UNALIGNED;
} }

View File

@ -54,8 +54,11 @@ public final class Epoll {
if (cause != null) { if (cause != null) {
UNAVAILABILITY_CAUSE = cause; UNAVAILABILITY_CAUSE = cause;
} else { } else {
UNAVAILABILITY_CAUSE = PlatformDependent.hasUnsafe() ? null : UNAVAILABILITY_CAUSE = PlatformDependent.hasUnsafe()
new IllegalStateException("sun.misc.Unsafe not available"); ? null
: new IllegalStateException(
"sun.misc.Unsafe not available",
PlatformDependent.getUnsafeUnavailabilityCause());
} }
} }

View File

@ -46,8 +46,11 @@ public final class KQueue {
if (cause != null) { if (cause != null) {
UNAVAILABILITY_CAUSE = cause; UNAVAILABILITY_CAUSE = cause;
} else { } else {
UNAVAILABILITY_CAUSE = PlatformDependent.hasUnsafe() ? null : UNAVAILABILITY_CAUSE = PlatformDependent.hasUnsafe()
new IllegalStateException("sun.misc.Unsafe not available"); ? null
: new IllegalStateException(
"sun.misc.Unsafe not available",
PlatformDependent.getUnsafeUnavailabilityCause());
} }
} }