# HG changeset patch # User dl # Date 1457030374 28800 # Node ID 7a020ad42ac096279f8a7f3aa439bd4fe26afb10 # Parent 52e0ee9847fb6c02bb1c37b9f48dfea727c3e2fd 8150417: Make ThreadLocalRandom more robust against static initialization cycles Reviewed-by: martin, psandoz, dholmes, mhaupt diff -r 52e0ee9847fb -r 7a020ad42ac0 jdk/src/java.base/share/classes/java/util/SplittableRandom.java --- a/jdk/src/java.base/share/classes/java/util/SplittableRandom.java Thu Mar 03 10:36:08 2016 -0800 +++ b/jdk/src/java.base/share/classes/java/util/SplittableRandom.java Thu Mar 03 10:39:34 2016 -0800 @@ -219,12 +219,20 @@ return seed += gamma; } + // IllegalArgumentException messages + static final String BAD_BOUND = "bound must be positive"; + static final String BAD_RANGE = "bound must be greater than origin"; + static final String BAD_SIZE = "size must be non-negative"; + /** * The seed generator for default constructors. */ - private static final AtomicLong defaultGen = new AtomicLong(initialSeed()); + private static final AtomicLong defaultGen + = new AtomicLong(mix64(System.currentTimeMillis()) ^ + mix64(System.nanoTime())); - private static long initialSeed() { + // at end of to survive static initialization circularity + static { if (java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Boolean run() { @@ -234,17 +242,10 @@ long s = (long)seedBytes[0] & 0xffL; for (int i = 1; i < 8; ++i) s = (s << 8) | ((long)seedBytes[i] & 0xffL); - return s; + defaultGen.set(s); } - return (mix64(System.currentTimeMillis()) ^ - mix64(System.nanoTime())); } - // IllegalArgumentException messages - static final String BAD_BOUND = "bound must be positive"; - static final String BAD_RANGE = "bound must be greater than origin"; - static final String BAD_SIZE = "size must be non-negative"; - /* * Internal versions of nextX methods used by streams, as well as * the public nextX(origin, bound) methods. These exist mainly to diff -r 52e0ee9847fb -r 7a020ad42ac0 jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java --- a/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java Thu Mar 03 10:36:08 2016 -0800 +++ b/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java Thu Mar 03 10:39:34 2016 -0800 @@ -125,53 +125,6 @@ * but we provide identical statistical properties. */ - /** Generates per-thread initialization/probe field */ - private static final AtomicInteger probeGenerator = new AtomicInteger(); - - /** - * The next seed for default constructors. - */ - private static final AtomicLong seeder = new AtomicLong(initialSeed()); - - private static long initialSeed() { - if (java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Boolean run() { - return Boolean.getBoolean("java.util.secureRandomSeed"); - }})) { - byte[] seedBytes = java.security.SecureRandom.getSeed(8); - long s = (long)seedBytes[0] & 0xffL; - for (int i = 1; i < 8; ++i) - s = (s << 8) | ((long)seedBytes[i] & 0xffL); - return s; - } - return (mix64(System.currentTimeMillis()) ^ - mix64(System.nanoTime())); - } - - /** - * The seed increment. - */ - private static final long GAMMA = 0x9e3779b97f4a7c15L; - - /** - * The increment for generating probe values. - */ - private static final int PROBE_INCREMENT = 0x9e3779b9; - - /** - * The increment of seeder per new instance. - */ - private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL; - - // Constants from SplittableRandom - private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53) - private static final float FLOAT_UNIT = 0x1.0p-24f; // 1.0f / (1 << 24) - - /** Rarely-used holder for the second of a pair of Gaussians */ - private static final ThreadLocal nextLocalGaussian = - new ThreadLocal<>(); - private static long mix64(long z) { z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL; z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L; @@ -194,9 +147,6 @@ initialized = true; // false during super() call } - /** The common ThreadLocalRandom */ - static final ThreadLocalRandom instance = new ThreadLocalRandom(); - /** * Initialize Thread fields for the current thread. Called only * when Thread.threadLocalRandomProbe is zero, indicating that a @@ -248,11 +198,6 @@ return (int)(mix64(nextSeed()) >>> (64 - bits)); } - // IllegalArgumentException messages - static final String BAD_BOUND = "bound must be positive"; - static final String BAD_RANGE = "bound must be greater than origin"; - static final String BAD_SIZE = "size must be non-negative"; - /** * The form of nextLong used by LongStream Spliterators. If * origin is greater than bound, acts as unbounded form of @@ -1050,6 +995,32 @@ return current(); } + // Static initialization + + /** + * The seed increment. + */ + private static final long GAMMA = 0x9e3779b97f4a7c15L; + + /** + * The increment for generating probe values. + */ + private static final int PROBE_INCREMENT = 0x9e3779b9; + + /** + * The increment of seeder per new instance. + */ + private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL; + + // Constants from SplittableRandom + private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53) + private static final float FLOAT_UNIT = 0x1.0p-24f; // 1.0f / (1 << 24) + + // IllegalArgumentException messages + static final String BAD_BOUND = "bound must be positive"; + static final String BAD_RANGE = "bound must be greater than origin"; + static final String BAD_SIZE = "size must be non-negative"; + // Unsafe mechanics private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe(); private static final long SEED; @@ -1067,4 +1038,36 @@ throw new Error(e); } } + + /** Rarely-used holder for the second of a pair of Gaussians */ + private static final ThreadLocal nextLocalGaussian = + new ThreadLocal<>(); + + /** Generates per-thread initialization/probe field */ + private static final AtomicInteger probeGenerator = new AtomicInteger(); + + /** The common ThreadLocalRandom */ + static final ThreadLocalRandom instance = new ThreadLocalRandom(); + + /** + * The next seed for default constructors. + */ + private static final AtomicLong seeder + = new AtomicLong(mix64(System.currentTimeMillis()) ^ + mix64(System.nanoTime())); + + // at end of to survive static initialization circularity + static { + if (java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Boolean run() { + return Boolean.getBoolean("java.util.secureRandomSeed"); + }})) { + byte[] seedBytes = java.security.SecureRandom.getSeed(8); + long s = (long)seedBytes[0] & 0xffL; + for (int i = 1; i < 8; ++i) + s = (s << 8) | ((long)seedBytes[i] & 0xffL); + seeder.set(s); + } + } }