< prev index next >

src/java.base/share/classes/java/lang/ClassLoader.java

Print this page

        

*** 35,68 **** import java.security.AccessControlContext; import java.security.CodeSource; import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.security.cert.Certificate; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Set; import java.util.Spliterator; import java.util.Spliterators; - import java.util.Stack; import java.util.Vector; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; import java.util.stream.Stream; import java.util.stream.StreamSupport; import jdk.internal.perf.PerfCounter; import jdk.internal.loader.BootLoader; import jdk.internal.loader.ClassLoaders; - import jdk.internal.misc.SharedSecrets; import jdk.internal.misc.Unsafe; import jdk.internal.misc.VM; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import sun.reflect.misc.ReflectUtil; import sun.security.util.SecurityConstants; --- 35,71 ---- import java.security.AccessControlContext; import java.security.CodeSource; import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.security.cert.Certificate; + import java.util.Arrays; import java.util.Collections; + import java.util.Deque; import java.util.Enumeration; import java.util.HashMap; + import java.util.HashSet; import java.util.Hashtable; + import java.util.LinkedList; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Set; import java.util.Spliterator; import java.util.Spliterators; import java.util.Vector; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; import java.util.stream.Stream; import java.util.stream.StreamSupport; import jdk.internal.perf.PerfCounter; import jdk.internal.loader.BootLoader; import jdk.internal.loader.ClassLoaders; import jdk.internal.misc.Unsafe; import jdk.internal.misc.VM; + import jdk.internal.ref.CleanerFactory; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import sun.reflect.misc.ReflectUtil; import sun.security.util.SecurityConstants;
*** 2373,2448 **** * * @see ClassLoader * @since 1.2 */ static class NativeLibrary { - // opaque handle to native library, used in native code. - long handle; - // the version of JNI environment the native library requires. - private int jniVersion; // the class from which the library is loaded, also indicates // the loader this native library belongs. ! private final Class<?> fromClass; // the canonicalized name of the native library. // or static library name ! String name; // Indicates if the native library is linked into the VM ! boolean isBuiltin; ! // Indicates if the native library is loaded ! boolean loaded; ! native void load(String name, boolean isBuiltin); ! native long find(String name); ! native void unload(String name, boolean isBuiltin); ! public NativeLibrary(Class<?> fromClass, String name, boolean isBuiltin) { this.name = name; this.fromClass = fromClass; this.isBuiltin = isBuiltin; } ! @SuppressWarnings("deprecation") ! protected void finalize() { synchronized (loadedLibraryNames) { ! if (fromClass.getClassLoader() != null && loaded) { ! /* remove the native library name */ ! int size = loadedLibraryNames.size(); ! for (int i = 0; i < size; i++) { ! if (name.equals(loadedLibraryNames.elementAt(i))) { ! loadedLibraryNames.removeElementAt(i); ! break; } } ! /* unload the library. */ ! ClassLoader.nativeLibraryContext.push(this); try { ! unload(name, isBuiltin); } finally { ! ClassLoader.nativeLibraryContext.pop(); ! } } } } ! // Invoked in the VM to determine the context class in ! // JNI_Load/JNI_Unload static Class<?> getFromClass() { ! return ClassLoader.nativeLibraryContext.peek().fromClass; } } ! // All native library names we've loaded. ! private static Vector<String> loadedLibraryNames = new Vector<>(); ! // Native libraries belonging to system classes. ! private static Vector<NativeLibrary> systemNativeLibraries ! = new Vector<>(); ! // Native libraries associated with the class loader. ! private Vector<NativeLibrary> nativeLibraries = new Vector<>(); ! // native libraries being loaded/unloaded. ! private static Stack<NativeLibrary> nativeLibraryContext = new Stack<>(); // The paths searched for libraries private static String usr_paths[]; private static String sys_paths[]; --- 2376,2539 ---- * * @see ClassLoader * @since 1.2 */ static class NativeLibrary { // the class from which the library is loaded, also indicates // the loader this native library belongs. ! final Class<?> fromClass; // the canonicalized name of the native library. // or static library name ! final String name; // Indicates if the native library is linked into the VM ! final boolean isBuiltin; ! ! // opaque handle to native library, used in native code. ! long handle; ! // the version of JNI environment the native library requires. ! int jniVersion; ! native boolean load0(String name, boolean isBuiltin); ! native long findEntry(String name); ! ! NativeLibrary(Class<?> fromClass, String name, boolean isBuiltin) { this.name = name; this.fromClass = fromClass; this.isBuiltin = isBuiltin; } ! /* ! * Loads the native library and registers for cleanup when its ! * associated class loader is unloaded ! */ ! boolean load() { ! if (handle != 0) { ! throw new InternalError("Native library " + name + " has been loaded"); ! } ! ! if (!load0(name, isBuiltin)) return false; ! ! // register the class loader for cleanup when unloaded ! // built class loaders are never unloaded ! ClassLoader loader = fromClass.getClassLoader(); ! if (loader != null && ! loader != getBuiltinPlatformClassLoader() && ! loader != getBuiltinAppClassLoader()) { ! CleanerFactory.cleaner().register(loader, ! new Unloader(name, handle, isBuiltin)); ! } ! return true; ! } ! ! static boolean loadLibrary(Class<?> fromClass, String name, boolean isBuiltin) { ! ClassLoader loader = ! fromClass == null ? null : fromClass.getClassLoader(); ! synchronized (loadedLibraryNames) { ! Map<String, NativeLibrary> libs = ! loader != null ? loader.nativeLibraries() : systemNativeLibraries(); ! if (libs.containsKey(name)) { ! return true; } + + if (loadedLibraryNames.contains(name)) { + throw new UnsatisfiedLinkError("Native Library " + name + + " already loaded in another classloader"); } ! ! /* ! * When a library is being loaded, JNI_OnLoad function can cause ! * another loadLibrary invocation that should succeed. ! * ! * We use a static stack to hold the list of libraries we are ! * loading because this can happen only when called by the ! * same thread because Runtime.load and Runtime.loadLibrary ! * are synchronous. ! * ! * If there is a pending load operation for the library, we ! * immediately return success; otherwise, we raise ! * UnsatisfiedLinkError. ! */ ! for (NativeLibrary lib : nativeLibraryContext) { ! if (name.equals(lib.name)) { ! if (loader == lib.fromClass.getClassLoader()) { ! return true; ! } else { ! throw new UnsatisfiedLinkError("Native Library " + ! name + " is being loaded in another classloader"); ! } ! } ! } ! NativeLibrary lib = new NativeLibrary(fromClass, name, isBuiltin); ! // load the native library ! nativeLibraryContext.push(lib); try { ! if (!lib.load()) return false; } finally { ! nativeLibraryContext.pop(); } + // register the loaded native library + loadedLibraryNames.add(name); + libs.put(name, lib); } + return true; } ! ! // Invoked in the VM to determine the context class in JNI_OnLoad ! // and JNI_OnUnload static Class<?> getFromClass() { ! return nativeLibraryContext.peek().fromClass; } + + // native libraries being loaded + static Deque<NativeLibrary> nativeLibraryContext = new LinkedList<>(); + + /* + * The run() method will be invoked when this class loader becomes + * phantom reachable to unload the native library. + */ + static class Unloader implements Runnable { + // This represents the context when a native library is unloaded + // and getFromClass() will return null, + static final NativeLibrary UNLOADER = + new NativeLibrary(null, "dummy", false); + final String name; + final long handle; + final boolean isBuiltin; + + Unloader(String name, long handle, boolean isBuiltin) { + if (handle == 0) { + throw new IllegalArgumentException( + "Invalid handle for native library " + name); } ! this.name = name; ! this.handle = handle; ! this.isBuiltin = isBuiltin; ! } ! @Override ! public void run() { ! synchronized (loadedLibraryNames) { ! /* remove the native library name */ ! loadedLibraryNames.remove(name); ! nativeLibraryContext.push(UNLOADER); ! try { ! unload(name, isBuiltin, handle); ! } finally { ! nativeLibraryContext.pop(); ! } ! } ! } ! } ! // JNI FindClass expects the caller class if invoked from JNI_OnLoad ! // and JNI_OnUnload is NativeLibrary class ! static native void unload(String name, boolean isBuiltin, long handle); ! } // The paths searched for libraries private static String usr_paths[]; private static String sys_paths[];
*** 2547,2560 **** return; } } } // Oops, it failed ! throw new UnsatisfiedLinkError("no " + name + " in java.library.path"); } ! static native String findBuiltinLib(String name); private static boolean loadLibrary0(Class<?> fromClass, final File file) { // Check to see if we're attempting to access a static library String name = findBuiltinLib(file.getName()); boolean isBuiltin = (name != null); --- 2638,2652 ---- return; } } } // Oops, it failed ! throw new UnsatisfiedLinkError("no " + name + ! " in java.library.path: " + Arrays.toString(usr_paths)); } ! private static native String findBuiltinLib(String name); private static boolean loadLibrary0(Class<?> fromClass, final File file) { // Check to see if we're attempting to access a static library String name = findBuiltinLib(file.getName()); boolean isBuiltin = (name != null);
*** 2571,2660 **** }); if (name == null) { return false; } } ! ClassLoader loader = ! (fromClass == null) ? null : fromClass.getClassLoader(); ! Vector<NativeLibrary> libs = ! loader != null ? loader.nativeLibraries : systemNativeLibraries; ! synchronized (libs) { ! int size = libs.size(); ! for (int i = 0; i < size; i++) { ! NativeLibrary lib = libs.elementAt(i); ! if (name.equals(lib.name)) { ! return true; ! } } ! synchronized (loadedLibraryNames) { ! if (loadedLibraryNames.contains(name)) { ! throw new UnsatisfiedLinkError ! ("Native Library " + ! name + ! " already loaded in another classloader"); ! } ! /* If the library is being loaded (must be by the same thread, ! * because Runtime.load and Runtime.loadLibrary are ! * synchronous). The reason is can occur is that the JNI_OnLoad ! * function can cause another loadLibrary invocation. ! * ! * Thus we can use a static stack to hold the list of libraries ! * we are loading. ! * ! * If there is a pending load operation for the library, we ! * immediately return success; otherwise, we raise ! * UnsatisfiedLinkError. */ ! int n = nativeLibraryContext.size(); ! for (int i = 0; i < n; i++) { ! NativeLibrary lib = nativeLibraryContext.elementAt(i); ! if (name.equals(lib.name)) { ! if (loader == lib.fromClass.getClassLoader()) { ! return true; ! } else { ! throw new UnsatisfiedLinkError ! ("Native Library " + ! name + ! " is being loaded in another classloader"); ! } ! } ! } ! NativeLibrary lib = new NativeLibrary(fromClass, name, isBuiltin); ! nativeLibraryContext.push(lib); ! try { ! lib.load(name, isBuiltin); ! } finally { ! nativeLibraryContext.pop(); } ! if (lib.loaded) { ! loadedLibraryNames.addElement(name); ! libs.addElement(lib); ! return true; } ! return false; } } } ! // Invoked in the VM class linking code. ! static long findNative(ClassLoader loader, String name) { ! Vector<NativeLibrary> libs = ! loader != null ? loader.nativeLibraries : systemNativeLibraries; ! synchronized (libs) { ! int size = libs.size(); ! for (int i = 0; i < size; i++) { ! NativeLibrary lib = libs.elementAt(i); ! long entry = lib.find(name); ! if (entry != 0) ! return entry; } } - return 0; } - // -- Assertion management -- final Object assertionLock; // The default toggle for assertion checking. --- 2663,2731 ---- }); if (name == null) { return false; } } ! return NativeLibrary.loadLibrary(fromClass, name, isBuiltin); } ! /* ! * Invoked in the VM class linking code. */ ! private static long findNative(ClassLoader loader, String name) { ! Map<String, NativeLibrary> libs = ! loader != null ? loader.nativeLibraries() : systemNativeLibraries(); ! if (libs.isEmpty()) ! return 0; ! ! // the native libraries map may be updated in another thread ! // when a native library is being loaded. No symbol will be ! // searched from it yet. ! for (NativeLibrary lib : libs.values()) { ! long entry = lib.findEntry(name); ! if (entry != 0) return entry; } ! return 0; } ! ! // All native library names we've loaded. ! // This also serves as the lock to obtain nativeLibraries ! // and write to nativeLibraryContext. ! private static final Set<String> loadedLibraryNames = new HashSet<>(); ! ! // Native libraries belonging to system classes. ! private static Map<String, NativeLibrary> systemNativeLibraries = null; ! ! // Native libraries associated with the class loader. ! private Map<String, NativeLibrary> nativeLibraries = null; ! ! /* ! * Returns the native libraries map associated with bootstrap class loader ! * This method will create the map at the first time when called. ! */ ! private static Map<String, NativeLibrary> systemNativeLibraries() { ! synchronized (loadedLibraryNames) { ! if (systemNativeLibraries == null) { ! systemNativeLibraries = new ConcurrentHashMap<>(); } + return systemNativeLibraries; } } ! /* ! * Returns the native libraries map associated with this class loader ! * This method will create the map at the first time when called. ! */ ! private Map<String, NativeLibrary> nativeLibraries() { ! synchronized (loadedLibraryNames) { ! if (nativeLibraries == null) { ! nativeLibraries = new ConcurrentHashMap<>(); } + return nativeLibraries; } } // -- Assertion management -- final Object assertionLock; // The default toggle for assertion checking.
< prev index next >