6977738: Deadlock between java.lang.ClassLoader and java.util.Properties
Reviewed-by: alanb, sherman, darcy, igor
--- a/jdk/make/java/java/FILES_java.gmk Mon Oct 11 10:55:04 2010 +0100
+++ b/jdk/make/java/java/FILES_java.gmk Mon Oct 11 20:22:27 2010 -0700
@@ -465,14 +465,11 @@
java/security/ProtectionDomain.java \
java/net/URLClassLoader.java \
java/net/URLConnection.java \
+ sun/misc/BootClassLoaderHook.java \
sun/misc/Launcher.java \
sun/misc/MetaIndex.java \
sun/misc/URLClassPath.java \
sun/misc/Version.java \
- sun/net/www/protocol/jar/Handler.java \
- sun/net/www/protocol/jar/JarURLConnection.java \
- sun/net/www/protocol/file/Handler.java \
- sun/net/www/protocol/file/FileURLConnection.java \
sun/misc/FileURLMapper.java \
sun/misc/MessageUtils.java \
sun/misc/GC.java \
@@ -482,6 +479,10 @@
sun/misc/JavaIOFileDescriptorAccess.java \
sun/misc/JavaNioAccess.java \
sun/misc/Perf.java \
- sun/misc/PerfCounter.java
+ sun/misc/PerfCounter.java \
+ sun/net/www/protocol/jar/Handler.java \
+ sun/net/www/protocol/jar/JarURLConnection.java \
+ sun/net/www/protocol/file/Handler.java \
+ sun/net/www/protocol/file/FileURLConnection.java
FILES_java = $(JAVA_JAVA_java)
--- a/jdk/src/share/classes/java/lang/Integer.java Mon Oct 11 10:55:04 2010 +0100
+++ b/jdk/src/share/classes/java/lang/Integer.java Mon Oct 11 20:22:27 2010 -0700
@@ -586,25 +586,13 @@
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
- * The cache is initialized on first usage. During VM initialization the
- * getAndRemoveCacheProperties method may be used to get and remove any system
- * properites that configure the cache size. At this time, the size of the
- * cache may be controlled by the -XX:AutoBoxCacheMax=<size> option.
+ * The cache is initialized on first usage. The size of the cache
+ * may be controlled by the -XX:AutoBoxCacheMax=<size> option.
+ * During VM initialization, java.lang.Integer.IntegerCache.high property
+ * may be set and saved in the private system properties in the
+ * sun.misc.VM class.
*/
- // value of java.lang.Integer.IntegerCache.high property (obtained during VM init)
- private static String integerCacheHighPropValue;
-
- static void getAndRemoveCacheProperties() {
- if (!sun.misc.VM.isBooted()) {
- Properties props = System.getProperties();
- integerCacheHighPropValue =
- (String)props.remove("java.lang.Integer.IntegerCache.high");
- if (integerCacheHighPropValue != null)
- System.setProperties(props); // remove from system props
- }
- }
-
private static class IntegerCache {
static final int low = -128;
static final int high;
@@ -613,6 +601,8 @@
static {
// high value may be configured by property
int h = 127;
+ String integerCacheHighPropValue =
+ sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
--- a/jdk/src/share/classes/java/lang/System.java Mon Oct 11 10:55:04 2010 +0100
+++ b/jdk/src/share/classes/java/lang/System.java Mon Oct 11 20:22:27 2010 -0700
@@ -53,7 +53,13 @@
*/
public final class System {
- /* First thing---register the natives */
+ /* register the natives via the static initializer.
+ *
+ * VM will invoke the initializeSystemClass method to complete
+ * the initialization for this class separated from clinit.
+ * Note that to use properties set by the VM, see the constraints
+ * described in the initializeSystemClass method.
+ */
private static native void registerNatives();
static {
registerNatives();
@@ -1096,17 +1102,21 @@
* Initialize the system class. Called after thread initialization.
*/
private static void initializeSystemClass() {
- props = new Properties();
- initProperties(props);
+ // There are certain system configurations that may be controlled by
+ // VM options such as the maximum amount of direct memory and
+ // Integer cache size used to support the object identity semantics
+ // of autoboxing. Typically, the library will obtain these values
+ // from the properties set by the VM. If the properties are for
+ // internal implementation use only, these properties should be
+ // removed from the system properties.
+ //
+ // See java.lang.Integer.IntegerCache and the
+ // sun.misc.VM.saveAndRemoveProperties method for example.
+ props = initSystemProperties();
+
lineSeparator = props.getProperty("line.separator");
sun.misc.Version.init();
- // Gets and removes system properties that configure the Integer
- // cache used to support the object identity semantics of autoboxing.
- // At this time, the size of the cache may be controlled by the
- // vm option -XX:AutoBoxCacheMax=<size>.
- Integer.getAndRemoveCacheProperties();
-
FileInputStream fdIn = new FileInputStream(FileDescriptor.in);
FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);
@@ -1127,17 +1137,6 @@
// classes are used.
sun.misc.VM.initializeOSEnvironment();
- // Set the maximum amount of direct memory. This value is controlled
- // by the vm option -XX:MaxDirectMemorySize=<size>. This method acts
- // as an initializer only if it is called before sun.misc.VM.booted().
- sun.misc.VM.maxDirectMemory();
-
- // Set a boolean to determine whether ClassLoader.loadClass accepts
- // array syntax. This value is controlled by the system property
- // "sun.lang.ClassLoader.allowArraySyntax". This method acts as
- // an initializer only if it is called before sun.misc.VM.booted().
- sun.misc.VM.allowArraySyntax();
-
// Subsystems that are invoked during initialization can invoke
// sun.misc.VM.isBooted() in order to avoid doing things that should
// wait until the application class loader has been set up.
@@ -1152,6 +1151,18 @@
setJavaLangAccess();
}
+ private static Properties initSystemProperties() {
+ Properties props = new Properties();
+ initProperties(props); // initialized by the VM
+
+ // Save a private copy of the system properties object that
+ // can only be accessed by the internal implementation. Remove
+ // certain system properties that are not intended for public access.
+ sun.misc.VM.saveAndRemoveProperties(props);
+
+ return props;
+ }
+
private static void setJavaLangAccess() {
// Allow privileged classes outside of java.lang
sun.misc.SharedSecrets.setJavaLangAccess(new sun.misc.JavaLangAccess(){
--- a/jdk/src/share/classes/java/util/Properties.java Mon Oct 11 10:55:04 2010 +0100
+++ b/jdk/src/share/classes/java/util/Properties.java Mon Oct 11 20:22:27 2010 -0700
@@ -705,7 +705,7 @@
* <code>Strings</code>.
*/
@Deprecated
- public synchronized void save(OutputStream out, String comments) {
+ public void save(OutputStream out, String comments) {
try {
store(out, comments);
} catch (IOException e) {
@@ -890,7 +890,7 @@
* @see #loadFromXML(InputStream)
* @since 1.5
*/
- public synchronized void storeToXML(OutputStream os, String comment)
+ public void storeToXML(OutputStream os, String comment)
throws IOException
{
if (os == null)
@@ -929,8 +929,7 @@
* @see #loadFromXML(InputStream)
* @since 1.5
*/
- public synchronized void storeToXML(OutputStream os, String comment,
- String encoding)
+ public void storeToXML(OutputStream os, String comment, String encoding)
throws IOException
{
if (os == null)
--- a/jdk/src/share/classes/java/util/XMLUtils.java Mon Oct 11 10:55:04 2010 +0100
+++ b/jdk/src/share/classes/java/util/XMLUtils.java Mon Oct 11 20:22:27 2010 -0700
@@ -141,14 +141,13 @@
comments.appendChild(doc.createTextNode(comment));
}
- Set keys = props.keySet();
- Iterator i = keys.iterator();
- while(i.hasNext()) {
- String key = (String)i.next();
- Element entry = (Element)properties.appendChild(
- doc.createElement("entry"));
- entry.setAttribute("key", key);
- entry.appendChild(doc.createTextNode(props.getProperty(key)));
+ synchronized (props) {
+ for (String key : props.stringPropertyNames()) {
+ Element entry = (Element)properties.appendChild(
+ doc.createElement("entry"));
+ entry.setAttribute("key", key);
+ entry.appendChild(doc.createTextNode(props.getProperty(key)));
+ }
}
emitDocument(doc, os, encoding);
}
--- a/jdk/src/share/classes/java/util/zip/ZipFile.java Mon Oct 11 10:55:04 2010 +0100
+++ b/jdk/src/share/classes/java/util/zip/ZipFile.java Mon Oct 11 20:22:27 2010 -0700
@@ -85,8 +85,7 @@
static {
// A system prpperty to disable mmap use to avoid vm crash when
// in-use zip file is accidently overwritten by others.
- String prop = AccessController.doPrivileged(
- new GetPropertyAction("sun.zip.disableMemoryMapping"));
+ String prop = sun.misc.VM.getSavedProperty("sun.zip.disableMemoryMapping");
usemmap = (prop == null ||
!(prop.length() == 0 || prop.equalsIgnoreCase("true")));
}
--- a/jdk/src/share/classes/sun/jkernel/DownloadManager.java Mon Oct 11 10:55:04 2010 +0100
+++ b/jdk/src/share/classes/sun/jkernel/DownloadManager.java Mon Oct 11 20:22:27 2010 -0700
@@ -25,13 +25,18 @@
package sun.jkernel;
import java.io.*;
+import java.net.URLStreamHandlerFactory;
+import java.net.URL;
+import java.net.MalformedURLException;
import java.security.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.jar.*;
import java.util.zip.*;
+import sun.misc.BootClassLoaderHook;
import sun.misc.Launcher;
-import sun.misc.BootClassLoaderHook;
+import sun.misc.URLClassPath;
+import sun.net.www.ParseUtil;
/**
* Handles the downloading of additional JRE components. The bootstrap class
@@ -658,31 +663,61 @@
return getAppDataLocalLow() + getKernelJREDir();
}
- /**
- * Returns an array of JAR files which have been added to the boot strap
- * class path since the JVM was first booted.
- */
- public static synchronized File[] getAdditionalBootStrapPaths() {
- return additionalBootStrapPaths != null ? additionalBootStrapPaths :
- new File[0];
- }
-
-
+ // To be revisited:
+ // How DownloadManager maintains its bootstrap class path.
+ // sun.misc.Launcher.getBootstrapClassPath() returns
+ // DownloadManager.getBootstrapClassPath() instead.
+ //
+ // So should no longer need to lock the Launcher.class.
+ // In addition, additionalBootStrapPaths is not really needed
+ // if it obtains the initial bootclasspath during DownloadManager's
+ // initialization.
private static void addEntryToBootClassPath(File path) {
// Must acquire these locks in this order
synchronized(Launcher.class) {
- synchronized(DownloadManager.class) {
+ synchronized(DownloadManager.class) {
File[] newBootStrapPaths = new File[
additionalBootStrapPaths.length + 1];
System.arraycopy(additionalBootStrapPaths, 0, newBootStrapPaths,
0, additionalBootStrapPaths.length);
newBootStrapPaths[newBootStrapPaths.length - 1] = path;
additionalBootStrapPaths = newBootStrapPaths;
- Launcher.flushBootstrapClassPath();
+ if (bootstrapClassPath != null)
+ bootstrapClassPath.addURL(getFileURL(path));
}
}
}
+ /**
+ * Returns the kernel's bootstrap class path which includes the additional
+ * JARs downloaded
+ */
+ private static URLClassPath bootstrapClassPath = null;
+ private synchronized static
+ URLClassPath getBootClassPath(URLClassPath bcp,
+ URLStreamHandlerFactory factory)
+ {
+ if (bootstrapClassPath == null) {
+ bootstrapClassPath = new URLClassPath(bcp.getURLs(), factory);
+ for (File path : additionalBootStrapPaths) {
+ bootstrapClassPath.addURL(getFileURL(path));
+ }
+ }
+ return bootstrapClassPath;
+ }
+
+ private static URL getFileURL(File file) {
+ try {
+ file = file.getCanonicalFile();
+ } catch (IOException e) {}
+
+ try {
+ return ParseUtil.fileToEncodedURL(file);
+ } catch (MalformedURLException e) {
+ // Should never happen since we specify the protocol...
+ throw new InternalError();
+ }
+ }
/**
* Scan through java.ext.dirs to see if the lib/ext directory is included.
@@ -1680,8 +1715,10 @@
}
}
- public File[] getAdditionalBootstrapPaths() {
- return DownloadManager.getAdditionalBootStrapPaths();
+ public URLClassPath getBootstrapClassPath(URLClassPath bcp,
+ URLStreamHandlerFactory factory)
+ {
+ return DownloadManager.getBootClassPath(bcp, factory);
}
public boolean isCurrentThreadPrefetching() {
--- a/jdk/src/share/classes/sun/misc/BootClassLoaderHook.java Mon Oct 11 10:55:04 2010 +0100
+++ b/jdk/src/share/classes/sun/misc/BootClassLoaderHook.java Mon Oct 11 20:22:27 2010 -0700
@@ -27,6 +27,8 @@
import java.io.File;
import java.io.IOException;
+import java.net.URLStreamHandlerFactory;
+import sun.misc.URLClassPath;
/**
* BootClassLoaderHook defines an interface for a hook to inject
@@ -94,20 +96,6 @@
}
}
- private static final File[] EMPTY_FILE_ARRAY = new File[0];
-
- /**
- * Returns bootstrap class paths added by the hook.
- */
- public static File[] getBootstrapPaths() {
- BootClassLoaderHook hook = getHook();
- if (hook != null) {
- return hook.getAdditionalBootstrapPaths();
- } else {
- return EMPTY_FILE_ARRAY;
- }
- }
-
/**
* Returns a pathname of a JAR or class that the hook loads
* per this loadClass request; or null.
@@ -133,10 +121,13 @@
public abstract boolean loadLibrary(String libname);
/**
- * Returns additional boot class paths added by the hook that
- * should be searched by the boot class loader.
+ * Returns a bootstrap class path constructed by the hook.
+ *
+ * @param bcp VM's bootstrap class path
+ * @param factory Launcher's URL stream handler
*/
- public abstract File[] getAdditionalBootstrapPaths();
+ public abstract URLClassPath getBootstrapClassPath(URLClassPath bcp,
+ URLStreamHandlerFactory factory);
/**
* Returns true if the current thread is in the process of doing
--- a/jdk/src/share/classes/sun/misc/Launcher.java Mon Oct 11 10:55:04 2010 +0100
+++ b/jdk/src/share/classes/sun/misc/Launcher.java Mon Oct 11 20:22:27 2010 -0700
@@ -47,7 +47,6 @@
import java.security.Permission;
import java.security.ProtectionDomain;
import java.security.CodeSource;
-import sun.security.action.GetPropertyAction;
import sun.security.util.SecurityConstants;
import sun.net.www.ParseUtil;
@@ -57,6 +56,8 @@
public class Launcher {
private static URLStreamHandlerFactory factory = new Factory();
private static Launcher launcher = new Launcher();
+ private static String bootClassPath =
+ System.getProperty("sun.boot.class.path");
public static Launcher getLauncher() {
return launcher;
@@ -227,7 +228,8 @@
File dir = new File(urls[i].getPath()).getParentFile();
if (dir != null && !dir.equals(prevDir)) {
// Look in architecture-specific subdirectory first
- String arch = System.getProperty("os.arch");
+ // Read from the saved system properties to avoid deadlock
+ String arch = VM.getSavedProperty("os.arch");
if (arch != null) {
File file = new File(new File(dir, arch), name);
if (file.exists()) {
@@ -377,19 +379,15 @@
}
}
- private static URLClassPath bootstrapClassPath;
-
- public static synchronized URLClassPath getBootstrapClassPath() {
- if (bootstrapClassPath == null) {
- String prop = AccessController.doPrivileged(
- new GetPropertyAction("sun.boot.class.path"));
+ private static class BootClassPathHolder {
+ static final URLClassPath bcp;
+ static {
URL[] urls;
- if (prop != null) {
- final String path = prop;
+ if (bootClassPath != null) {
urls = AccessController.doPrivileged(
new PrivilegedAction<URL[]>() {
public URL[] run() {
- File[] classPath = getClassPath(path);
+ File[] classPath = getClassPath(bootClassPath);
int len = classPath.length;
Set<File> seenDirs = new HashSet<File>();
for (int i = 0; i < len; i++) {
@@ -410,25 +408,16 @@
} else {
urls = new URL[0];
}
-
- bootstrapClassPath = new URLClassPath(urls, factory);
- final File[] additionalBootStrapPaths =
- BootClassLoaderHook.getBootstrapPaths();
- AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() {
- for (int i=0; i<additionalBootStrapPaths.length; i++) {
- bootstrapClassPath.addURL(
- getFileURL(additionalBootStrapPaths[i]));
- }
- return null;
- }
- });
+ bcp = new URLClassPath(urls, factory);
}
- return bootstrapClassPath;
}
- public static synchronized void flushBootstrapClassPath() {
- bootstrapClassPath = null;
+ public static URLClassPath getBootstrapClassPath() {
+ URLClassPath bcp = BootClassPathHolder.bcp;
+ // if DownloadManager is installed, return the bootstrap class path
+ // maintained by the Java kernel
+ BootClassLoaderHook hook = BootClassLoaderHook.getHook();
+ return hook == null ? bcp : hook.getBootstrapClassPath(bcp, factory);
}
private static URL[] pathToURLs(File[] path) {
--- a/jdk/src/share/classes/sun/misc/VM.java Mon Oct 11 10:55:04 2010 +0100
+++ b/jdk/src/share/classes/sun/misc/VM.java Mon Oct 11 20:22:27 2010 -0700
@@ -170,33 +170,11 @@
//
private static long directMemory = 64 * 1024 * 1024;
- // If this method is invoked during VM initialization, it initializes the
- // maximum amount of allocatable direct buffer memory (in bytes) from the
- // system property sun.nio.MaxDirectMemorySize. The system property will
- // be removed when it is accessed.
- //
- // If this method is invoked after the VM is booted, it returns the
- // maximum amount of allocatable direct buffer memory.
+ // Returns the maximum amount of allocatable direct buffer memory.
+ // The directMemory variable is initialized during system initialization
+ // in the saveAndRemoveProperties method.
//
public static long maxDirectMemory() {
- if (booted)
- return directMemory;
-
- Properties p = System.getProperties();
- String s = (String)p.remove("sun.nio.MaxDirectMemorySize");
- System.setProperties(p);
-
- if (s != null) {
- if (s.equals("-1")) {
- // -XX:MaxDirectMemorySize not given, take default
- directMemory = Runtime.getRuntime().maxMemory();
- } else {
- long l = Long.parseLong(s);
- if (l > -1)
- directMemory = l;
- }
- }
-
return directMemory;
}
@@ -212,26 +190,82 @@
private static boolean defaultAllowArraySyntax = false;
private static boolean allowArraySyntax = defaultAllowArraySyntax;
- // If this method is invoked during VM initialization, it initializes the
- // allowArraySyntax boolean based on the value of the system property
+ // The allowArraySyntax boolean is initialized during system initialization
+ // in the saveAndRemoveProperties method.
+ //
+ // It is initialized based on the value of the system property
// "sun.lang.ClassLoader.allowArraySyntax". If the system property is not
// provided, the default for 1.5 is "true". In 1.6, the default will be
// "false". If the system property is provided, then the value of
// allowArraySyntax will be equal to "true" if Boolean.parseBoolean()
// returns "true". Otherwise, the field will be set to "false".
//
- // If this method is invoked after the VM is booted, it returns the
- // allowArraySyntax boolean set during initialization.
+ public static boolean allowArraySyntax() {
+ return allowArraySyntax;
+ }
+
+ /**
+ * Returns the system property of the specified key saved at
+ * system initialization time. This method should only be used
+ * for the system properties that are not changed during runtime.
+ * It accesses a private copy of the system properties so
+ * that user's locking of the system properties object will not
+ * cause the library to deadlock.
+ *
+ * Note that the saved system properties do not include
+ * the ones set by sun.misc.Version.init().
+ *
+ */
+ public static String getSavedProperty(String key) {
+ if (savedProps.isEmpty())
+ throw new IllegalStateException("Should be non-empty if initialized");
+
+ return savedProps.getProperty(key);
+ }
+
+ private static final Properties savedProps = new Properties();
+
+ // Save a private copy of the system properties and remove
+ // the system properties that are not intended for public access.
//
- public static boolean allowArraySyntax() {
- if (!booted) {
- String s
- = System.getProperty("sun.lang.ClassLoader.allowArraySyntax");
- allowArraySyntax = (s == null
- ? defaultAllowArraySyntax
- : Boolean.parseBoolean(s));
+ // This method can only be invoked during system initialization.
+ public static void saveAndRemoveProperties(Properties props) {
+ if (booted)
+ throw new IllegalStateException("System initialization has completed");
+
+ savedProps.putAll(props);
+
+ // Set the maximum amount of direct memory. This value is controlled
+ // by the vm option -XX:MaxDirectMemorySize=<size>.
+ // The maximum amount of allocatable direct buffer memory (in bytes)
+ // from the system property sun.nio.MaxDirectMemorySize set by the VM.
+ // The system property will be removed.
+ String s = (String)props.remove("sun.nio.MaxDirectMemorySize");
+ if (s != null) {
+ if (s.equals("-1")) {
+ // -XX:MaxDirectMemorySize not given, take default
+ directMemory = Runtime.getRuntime().maxMemory();
+ } else {
+ long l = Long.parseLong(s);
+ if (l > -1)
+ directMemory = l;
+ }
}
- return allowArraySyntax;
+
+ // Set a boolean to determine whether ClassLoader.loadClass accepts
+ // array syntax. This value is controlled by the system property
+ // "sun.lang.ClassLoader.allowArraySyntax".
+ s = props.getProperty("sun.lang.ClassLoader.allowArraySyntax");
+ allowArraySyntax = (s == null
+ ? defaultAllowArraySyntax
+ : Boolean.parseBoolean(s));
+
+ // Remove other private system properties
+ // used by java.lang.Integer.IntegerCache
+ props.remove("java.lang.Integer.IntegerCache.high");
+
+ // used by java.util.zip.ZipFile
+ props.remove("sun.zip.disableMemoryMapping");
}
// Initialize any miscellenous operating system settings that need to be
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ClassLoader/deadlock/GetResource.java Mon Oct 11 20:22:27 2010 -0700
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.Properties;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.BrokenBarrierException;
+import java.io.IOException;
+import java.net.URL;
+
+/* @test
+ * @bug 6977738
+ * @summary Test ClassLoader.getResource() that should not deadlock
+ # if another thread is holding the system properties object
+ *
+ * @build GetResource
+ * @run main GetResource
+ */
+
+public class GetResource {
+ CyclicBarrier go = new CyclicBarrier(2);
+ CyclicBarrier done = new CyclicBarrier(2);
+ Thread t1, t2;
+ public GetResource() {
+ t1 = new Thread() {
+ public void run() {
+ Properties prop = System.getProperties();
+ synchronized (prop) {
+ System.out.println("Thread 1 ready");
+ try {
+ go.await();
+ prop.put("property", "value");
+ prop.store(System.out, "");
+ done.await(); // keep holding the lock until t2 finishes
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } catch (BrokenBarrierException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ System.out.println("Thread 1 exits");
+ }
+ };
+
+ t2 = new Thread() {
+ public void run() {
+ System.out.println("Thread 2 ready");
+ try {
+ go.await(); // wait until t1 holds the lock of the system properties
+
+ URL u1 = Thread.currentThread().getContextClassLoader().getResource("unknownresource");
+ URL u2 = Thread.currentThread().getContextClassLoader().getResource("sun/util/resources/CalendarData.class");
+ if (u2 == null) {
+ throw new RuntimeException("Test failed: resource not found");
+ }
+ done.await();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } catch (BrokenBarrierException e) {
+ throw new RuntimeException(e);
+ }
+ System.out.println("Thread 2 exits");
+ }
+ };
+ }
+
+ public void run() throws Exception {
+ t1.start();
+ t2.start();
+ try {
+ t1.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ throw e;
+ }
+ try {
+ t2.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ throw e;
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ new GetResource().run();
+ }
+}
--- a/jdk/test/sun/misc/BootClassLoaderHook/TestHook.java Mon Oct 11 10:55:04 2010 +0100
+++ b/jdk/test/sun/misc/BootClassLoaderHook/TestHook.java Mon Oct 11 20:22:27 2010 -0700
@@ -24,7 +24,10 @@
import java.io.File;
import java.util.TreeSet;
import java.util.Set;
+import java.net.URLStreamHandlerFactory;
import sun.misc.BootClassLoaderHook;
+import sun.misc.URLClassPath;
+
/* @test
* @bug 6888802
@@ -68,10 +71,6 @@
for (String s : copy) {
System.out.println(" Loaded " + s);
}
-
- if (BootClassLoaderHook.getBootstrapPaths().length > 0) {
- throw new RuntimeException("Unexpected returned value from getBootstrapPaths()");
- }
}
private static void testHook() throws Exception {
@@ -98,8 +97,9 @@
return false;
}
- public File[] getAdditionalBootstrapPaths() {
- return new File[0];
+ public URLClassPath getBootstrapClassPath(URLClassPath bcp,
+ URLStreamHandlerFactory factory) {
+ return bcp;
}
public boolean isCurrentThreadPrefetching() {