< prev index next >

src/java.base/share/classes/jdk/internal/loader/NativeLibraries.java

Print this page

        

*** 22,41 **** --- 22,43 ---- * or visit www.oracle.com if you need additional information or have any * questions. */ package jdk.internal.loader; + import jdk.internal.misc.VM; import jdk.internal.ref.CleanerFactory; import jdk.internal.util.StaticProperty; import java.io.File; import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayDeque; import java.util.Deque; import java.util.HashSet; + import java.util.Objects; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /**
*** 50,77 **** * has already been loaded by a class loader with another class loader * will fail. */ public final class NativeLibraries { ! private final Map<String, NativeLibrary> libraries = new ConcurrentHashMap<>(); private final ClassLoader loader; ! private final Class<?> caller; // may be null. If not null, this is used as ! // fromClass as a fast-path. See loadLibrary(String name). private final boolean searchJavaLibraryPath; ! public NativeLibraries(ClassLoader loader) { // for null loader, default the caller to this class and // do not search java.library.path ! this(loader, loader != null ? null : NativeLibraries.class, loader != null ? true : false); } ! public NativeLibraries(ClassLoader loader, Class<?> caller, boolean searchJavaLibraryPath) { ! if (caller != null && caller.getClassLoader() != loader) { ! throw new IllegalArgumentException(caller.getName() + " must be defined by " + loader); } ! this.loader = loader; this.caller = caller; this.searchJavaLibraryPath = searchJavaLibraryPath; } /* * Find the address of the given symbol name from the native libraries * loaded in this NativeLibraries instance. --- 52,128 ---- * has already been loaded by a class loader with another class loader * will fail. */ public final class NativeLibraries { ! private final Map<String, NativeLibraryImpl> libraries = new ConcurrentHashMap<>(); private final ClassLoader loader; ! // caller, if non-null, is the fromClass parameter for NativeLibraries::loadLibrary ! // unless specified ! private final Class<?> caller; // may be null private final boolean searchJavaLibraryPath; + // loading JNI native libraries + private final boolean isJNI; ! /** ! * Creates a NativeLibraries instance for loading JNI native libraries ! * via for System::loadLibrary use. ! * ! * 1. Support of auto-unloading. The loaded native libraries are unloaded ! * when the class loader is reclaimed. ! * 2. Support of linking of native method. See JNI spec. ! * 3. Restriction on a native library that can only be loaded by one class loader. ! * Each class loader manages its own set of native libraries. ! * The same JNI native library cannot be loaded into more than one class loader. ! * ! * This static factory method is intended only for System::loadLibrary use. ! * ! * @see <a href="${docroot}/specs/jni/invocation.html##library-and-version-management"> ! * JNI Specification: Library and Version Management</a> ! */ ! public static NativeLibraries jniNativeLibraries(ClassLoader loader) { ! return new NativeLibraries(loader); ! } ! ! /** ! * Creates a raw NativeLibraries instance that has the following properties: ! * 1. Native libraries loaded in this raw NativeLibraries instance are ! * not JNI native libraries. Hence JNI_OnLoad and JNI_OnUnload will ! * be ignored. No support for linking of native method. ! * 2. Native libraries not auto-unloaded. They may be explicitly unloaded ! * via NativeLibraries::unload. ! * 3. No relationship with class loaders. ! * ! * This static factory method is restricted for JDK trusted class use. ! */ ! public static NativeLibraries rawNativeLibraries(Class<?> trustedCaller, ! boolean searchJavaLibraryPath) { ! return new NativeLibraries(trustedCaller, searchJavaLibraryPath); ! } ! ! private NativeLibraries(ClassLoader loader) { // for null loader, default the caller to this class and // do not search java.library.path ! this.loader = loader; ! this.caller = loader != null ? null : NativeLibraries.class; ! this.searchJavaLibraryPath = loader != null ? true : false; ! this.isJNI = true; } ! ! /* ! * Constructs a NativeLibraries instance of no relationship with class loaders ! * and disabled auto unloading. ! */ ! private NativeLibraries(Class<?> caller, boolean searchJavaLibraryPath) { ! Objects.requireNonNull(caller); ! if (!VM.isSystemDomainLoader(caller.getClassLoader())) { ! throw new IllegalArgumentException("must be JDK trusted class"); } ! this.loader = caller.getClassLoader(); this.caller = caller; this.searchJavaLibraryPath = searchJavaLibraryPath; + this.isJNI = false; } /* * Find the address of the given symbol name from the native libraries * loaded in this NativeLibraries instance.
*** 167,181 **** name + " is being loaded in another classloader"); } } } ! NativeLibraryImpl lib = new NativeLibraryImpl(fromClass, name, isBuiltin); // load the native library nativeLibraryContext.push(lib); try { ! if (!lib.open()) return null; } finally { nativeLibraryContext.pop(); } // register the loaded native library loadedLibraryNames.add(name); --- 218,247 ---- name + " is being loaded in another classloader"); } } } ! NativeLibraryImpl lib = new NativeLibraryImpl(fromClass, name, isBuiltin, isJNI); // load the native library nativeLibraryContext.push(lib); try { ! if (!lib.open()) { ! return null; // fail to open the native library ! } ! // auto unloading is only supported for JNI native libraries ! // loaded by custom class loaders that can be unloaded. ! // built-in class loaders are never unloaded. ! boolean autoUnload = isJNI && !VM.isSystemDomainLoader(loader) ! && loader != ClassLoaders.appClassLoader(); ! if (autoUnload) { ! // register the loaded native library for auto unloading ! // when the class loader is reclaimed, all native libraries ! // loaded that class loader will be unloaded. ! // The entries in the libraries map are not removed since ! // the entire map will be reclaimed altogether. ! CleanerFactory.cleaner().register(loader, lib.unloader()); ! } } finally { nativeLibraryContext.pop(); } // register the loaded native library loadedLibraryNames.add(name);
*** 216,225 **** --- 282,311 ---- lib = findFromPaths(LibraryPaths.USER_PATHS, fromClass, name); } return lib; } + /** + * Unloads the given native library + * + * @param lib native library + */ + public void unload(NativeLibrary lib) { + if (isJNI) { + throw new UnsupportedOperationException("explicit unloading cannot be used with auto unloading"); + } + Objects.requireNonNull(lib); + synchronized (loadedLibraryNames) { + NativeLibraryImpl nl = libraries.remove(lib.name()); + if (nl != lib) { + throw new IllegalArgumentException(lib.name() + " not loaded by this NativeLibraries instance"); + } + // unload the native library and also remove from the global name registry + nl.unloader().run(); + } + } + private NativeLibrary findFromPaths(String[] paths, Class<?> fromClass, String name) { for (String path : paths) { File libfile = new File(path, System.mapLibraryName(name)); NativeLibrary nl = loadLibrary(fromClass, libfile); if (nl != null) {
*** 253,272 **** // 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; ! NativeLibraryImpl(Class<?> fromClass, String name, boolean isBuiltin) { this.fromClass = fromClass; this.name = name; this.isBuiltin = isBuiltin; } @Override public String name() { return name; --- 339,363 ---- // 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; + // Indicate if this is JNI native library + final boolean isJNI; // opaque handle to native library, used in native code. long handle; // the version of JNI environment the native library requires. int jniVersion; ! NativeLibraryImpl(Class<?> fromClass, String name, boolean isBuiltin, boolean isJNI) { ! assert !isBuiltin || isJNI : "a builtin native library must be JNI library"; ! this.fromClass = fromClass; this.name = name; this.isBuiltin = isBuiltin; + this.isJNI = isJNI; } @Override public String name() { return name;
*** 275,304 **** @Override public long find(String name) { return findEntry0(this, name); } /* ! * Loads the native library and registers for cleanup when its ! * associated class loader is unloaded */ boolean open() { if (handle != 0) { throw new InternalError("Native library " + name + " has been loaded"); } ! if (!load(this, name, isBuiltin)) return false; ! ! // register the class loader for cleanup when unloaded ! // builtin class loaders are never unloaded ! ClassLoader loader = fromClass != null ? fromClass.getClassLoader() : null; ! if (loader != null && ! loader != ClassLoaders.platformClassLoader() && ! loader != ClassLoaders.appClassLoader()) { ! CleanerFactory.cleaner().register(loader, new Unloader(name, handle, isBuiltin)); ! } ! return true; } } /* * The run() method will be invoked when this class loader becomes --- 366,388 ---- @Override public long find(String name) { return findEntry0(this, name); } + Runnable unloader() { + return new Unloader(name, handle, isBuiltin, isJNI); + } + /* ! * Loads the named native library */ boolean open() { if (handle != 0) { throw new InternalError("Native library " + name + " has been loaded"); } ! return load(this, name, isBuiltin, isJNI); } } /* * The run() method will be invoked when this class loader becomes
*** 306,342 **** */ static class Unloader implements Runnable { // This represents the context when a native library is unloaded // and getFromClass() will return null, static final NativeLibraryImpl UNLOADER = ! new NativeLibraryImpl(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 (NativeLibraries.loadedLibraryNames) { /* remove the native library name */ ! NativeLibraries.loadedLibraryNames.remove(name); ! NativeLibraries.nativeLibraryContext.push(UNLOADER); try { ! unload(name, isBuiltin, handle); } finally { ! NativeLibraries.nativeLibraryContext.pop(); } } } } --- 390,431 ---- */ static class Unloader implements Runnable { // This represents the context when a native library is unloaded // and getFromClass() will return null, static final NativeLibraryImpl UNLOADER = ! new NativeLibraryImpl(null, "dummy", false, false); final String name; final long handle; final boolean isBuiltin; + final boolean isJNI; ! Unloader(String name, long handle, boolean isBuiltin, boolean isJNI) { ! assert !isBuiltin || isJNI : "a builtin native library must be JNI library"; if (handle == 0) { throw new IllegalArgumentException( "Invalid handle for native library " + name); } this.name = name; this.handle = handle; this.isBuiltin = isBuiltin; + this.isJNI = isJNI; } @Override public void run() { ! synchronized (loadedLibraryNames) { /* remove the native library name */ ! if (!loadedLibraryNames.remove(name)) { ! throw new IllegalStateException(name + " has already been unloaded"); ! } ! nativeLibraryContext.push(UNLOADER); try { ! unload(name, isBuiltin, isJNI, handle); } finally { ! nativeLibraryContext.pop(); } } } }
*** 369,378 **** return nativeLibraryContext.peek().fromClass; } // JNI FindClass expects the caller class if invoked from JNI_OnLoad // and JNI_OnUnload is NativeLibrary class ! private static native boolean load(NativeLibraryImpl impl, String name, boolean isBuiltin); ! private static native void unload(String name, boolean isBuiltin, long handle); private static native String findBuiltinLib(String name); private static native long findEntry0(NativeLibraryImpl lib, String name); } --- 458,467 ---- return nativeLibraryContext.peek().fromClass; } // JNI FindClass expects the caller class if invoked from JNI_OnLoad // and JNI_OnUnload is NativeLibrary class ! private static native boolean load(NativeLibraryImpl impl, String name, boolean isBuiltin, boolean isJNI); ! private static native void unload(String name, boolean isBuiltin, boolean isJNI, long handle); private static native String findBuiltinLib(String name); private static native long findEntry0(NativeLibraryImpl lib, String name); }
< prev index next >