< prev index next >

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

Print this page

  1 /*
  2  * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any

138      * @param name      library name
139      * @param isBuiltin built-in library
140      * @throws UnsatisfiedLinkError if the native library has already been loaded
141      *      and registered in another NativeLibraries
142      */
143     private NativeLibrary loadLibrary(Class<?> fromClass, String name, boolean isBuiltin) {
144         ClassLoader loader = (fromClass == null) ? null : fromClass.getClassLoader();
145         if (this.loader != loader) {
146             throw new InternalError(fromClass.getName() + " not allowed to load library");
147         }
148 
149         acquireNativeLibraryLock(name);
150         try {
151             // find if this library has already been loaded and registered in this NativeLibraries
152             NativeLibrary cached = libraries.get(name);
153             if (cached != null) {
154                 return cached;
155             }
156 
157             // cannot be loaded by other class loaders
158             if (loadedLibraryNames.contains(name)) {
159                 throw new UnsatisfiedLinkError("Native Library " + name +
160                         " already loaded in another classloader");
161             }
162 
163             /*
164              * When a library is being loaded, JNI_OnLoad function can cause
165              * another loadLibrary invocation that should succeed.
166              *
167              * Each thread maintains its own stack to hold the list of
168              * libraries it is loading.
169              *
170              * If there is a pending load operation for the library, we
171              * immediately return success; if the pending load is from
172              * a different class loader, we raise UnsatisfiedLinkError.
173              */
174             for (NativeLibraryImpl lib : NativeLibraryContext.current()) {
175                 if (name.equals(lib.name())) {
176                     if (loader == lib.fromClass.getClassLoader()) {
177                         return lib;
178                     } else {

188             try {
189                 if (!lib.open()) {
190                     return null;    // fail to open the native library
191                 }
192                 // auto unloading is only supported for JNI native libraries
193                 // loaded by custom class loaders that can be unloaded.
194                 // built-in class loaders are never unloaded.
195                 boolean autoUnload = !VM.isSystemDomainLoader(loader) && loader != ClassLoaders.appClassLoader();
196                 if (autoUnload) {
197                     // register the loaded native library for auto unloading
198                     // when the class loader is reclaimed, all native libraries
199                     // loaded that class loader will be unloaded.
200                     // The entries in the libraries map are not removed since
201                     // the entire map will be reclaimed altogether.
202                     CleanerFactory.cleaner().register(loader, lib.unloader());
203                 }
204             } finally {
205                 NativeLibraryContext.pop();
206             }
207             // register the loaded native library
208             loadedLibraryNames.add(name);
209             libraries.put(name, lib);
210             return lib;
211         } finally {
212             releaseNativeLibraryLock(name);
213         }
214     }
215 
216     /**
217      * Loads a native library from the system library path and java library path.
218      *
219      * @param name library name
220      *
221      * @throws UnsatisfiedLinkError if the native library has already been loaded
222      *      and registered in another NativeLibraries
223      */
224     public NativeLibrary loadLibrary(String name) {
225         assert name.indexOf(File.separatorChar) < 0;
226         return loadLibrary(caller, name);
227     }
228 
229     /**
230      * Loads a native library from the system library path and java library path.
231      *
232      * @param name library name
233      * @param fromClass the caller class calling System::loadLibrary
234      *
235      * @throws UnsatisfiedLinkError if the native library has already been loaded
236      *      and registered in another NativeLibraries
237      */
238     public NativeLibrary loadLibrary(Class<?> fromClass, String name) {
239         assert name.indexOf(File.separatorChar) < 0;
240 
241         NativeLibrary lib = findFromPaths(LibraryPaths.SYS_PATHS, fromClass, name);
242         if (lib == null && searchJavaLibraryPath) {
243             lib = findFromPaths(LibraryPaths.USER_PATHS, fromClass, name);
244         }
245         return lib;
246     }
247 





248     private NativeLibrary findFromPaths(String[] paths, Class<?> fromClass, String name) {
249         for (String path : paths) {
250             File libfile = new File(path, System.mapLibraryName(name));
251             NativeLibrary nl = loadLibrary(fromClass, libfile);
252             if (nl != null) {
253                 return nl;
254             }
255             libfile = ClassLoaderHelper.mapAlternativeName(libfile);
256             if (libfile != null) {
257                 nl = loadLibrary(fromClass, libfile);
258                 if (nl != null) {
259                     return nl;
260                 }
261             }
262         }
263         return null;
264     }
265 
266     /**
267      * NativeLibraryImpl denotes a loaded native library instance.

358         final String name;
359         final long handle;
360         final boolean isBuiltin;
361 
362         Unloader(String name, long handle, boolean isBuiltin) {
363             if (handle == 0) {
364                 throw new IllegalArgumentException(
365                         "Invalid handle for native library " + name);
366             }
367 
368             this.name = name;
369             this.handle = handle;
370             this.isBuiltin = isBuiltin;
371         }
372 
373         @Override
374         public void run() {
375             acquireNativeLibraryLock(name);
376             try {
377                 /* remove the native library name */
378                 if (!loadedLibraryNames.remove(name)) {
379                     throw new IllegalStateException(name + " has already been unloaded");
380                 }
381                 NativeLibraryContext.push(UNLOADER);
382                 try {
383                     unload(name, isBuiltin, handle);
384                 } finally {
385                     NativeLibraryContext.pop();
386                 }
387             } finally {
388                 releaseNativeLibraryLock(name);
389             }
390         }
391     }
392 
393     /*
394      * Holds system and user library paths derived from the
395      * {@code java.library.path} and {@code sun.boot.library.path} system
396      * properties. The system properties are eagerly read at bootstrap, then
397      * lazily parsed on first use to avoid initialization ordering issues.
398      */
399     static class LibraryPaths {
400         // The paths searched for libraries
401         static final String[] SYS_PATHS = ClassLoaderHelper.parsePath(StaticProperty.sunBootLibraryPath());
402         static final String[] USER_PATHS = ClassLoaderHelper.parsePath(StaticProperty.javaLibraryPath());
403     }
404 
405     // All native libraries we've loaded.
406     private static final Set<String> loadedLibraryNames =



407             ConcurrentHashMap.newKeySet();

408 
409     // reentrant lock class that allows exact counting (with external synchronization)
410     @SuppressWarnings("serial")
411     private static final class CountedLock extends ReentrantLock {
412 
413         private int counter = 0;
414 
415         public void increment() {
416             if (counter == Integer.MAX_VALUE) {
417                 // prevent overflow
418                 throw new Error("Maximum lock count exceeded");
419             }
420             ++counter;
421         }
422 
423         public void decrement() {
424             --counter;
425         }
426 
427         public int getCounter() {

  1 /*
  2  * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any

138      * @param name      library name
139      * @param isBuiltin built-in library
140      * @throws UnsatisfiedLinkError if the native library has already been loaded
141      *      and registered in another NativeLibraries
142      */
143     private NativeLibrary loadLibrary(Class<?> fromClass, String name, boolean isBuiltin) {
144         ClassLoader loader = (fromClass == null) ? null : fromClass.getClassLoader();
145         if (this.loader != loader) {
146             throw new InternalError(fromClass.getName() + " not allowed to load library");
147         }
148 
149         acquireNativeLibraryLock(name);
150         try {
151             // find if this library has already been loaded and registered in this NativeLibraries
152             NativeLibrary cached = libraries.get(name);
153             if (cached != null) {
154                 return cached;
155             }
156 
157             // cannot be loaded by other class loaders
158             if (Holder.loadedLibraryNames.contains(name)) {
159                 throw new UnsatisfiedLinkError("Native Library " + name +
160                         " already loaded in another classloader");
161             }
162 
163             /*
164              * When a library is being loaded, JNI_OnLoad function can cause
165              * another loadLibrary invocation that should succeed.
166              *
167              * Each thread maintains its own stack to hold the list of
168              * libraries it is loading.
169              *
170              * If there is a pending load operation for the library, we
171              * immediately return success; if the pending load is from
172              * a different class loader, we raise UnsatisfiedLinkError.
173              */
174             for (NativeLibraryImpl lib : NativeLibraryContext.current()) {
175                 if (name.equals(lib.name())) {
176                     if (loader == lib.fromClass.getClassLoader()) {
177                         return lib;
178                     } else {

188             try {
189                 if (!lib.open()) {
190                     return null;    // fail to open the native library
191                 }
192                 // auto unloading is only supported for JNI native libraries
193                 // loaded by custom class loaders that can be unloaded.
194                 // built-in class loaders are never unloaded.
195                 boolean autoUnload = !VM.isSystemDomainLoader(loader) && loader != ClassLoaders.appClassLoader();
196                 if (autoUnload) {
197                     // register the loaded native library for auto unloading
198                     // when the class loader is reclaimed, all native libraries
199                     // loaded that class loader will be unloaded.
200                     // The entries in the libraries map are not removed since
201                     // the entire map will be reclaimed altogether.
202                     CleanerFactory.cleaner().register(loader, lib.unloader());
203                 }
204             } finally {
205                 NativeLibraryContext.pop();
206             }
207             // register the loaded native library
208             Holder.loadedLibraryNames.add(name);
209             libraries.put(name, lib);
210             return lib;
211         } finally {
212             releaseNativeLibraryLock(name);
213         }
214     }
215 
216     /**
217      * Loads a native library from the system library path and java library path.
218      *
219      * @param name library name
220      *
221      * @throws UnsatisfiedLinkError if the native library has already been loaded
222      *      and registered in another NativeLibraries
223      */
224     public NativeLibrary loadLibrary(String name) {
225         assert name.indexOf(File.separatorChar) < 0;
226         return loadLibrary(caller, name);
227     }
228 
229     /**
230      * Loads a native library from the system library path and java library path.
231      *
232      * @param name library name
233      * @param fromClass the caller class calling System::loadLibrary
234      *
235      * @throws UnsatisfiedLinkError if the native library has already been loaded
236      *      and registered in another NativeLibraries
237      */
238     public NativeLibrary loadLibrary(Class<?> fromClass, String name) {
239         assert name.indexOf(File.separatorChar) < 0;
240 
241         NativeLibrary lib = findFromPaths(LibraryPaths.SYS_PATHS, fromClass, name);
242         if (lib == null && searchJavaLibraryPath) {
243             lib = findFromPaths(LibraryPaths.USER_PATHS, fromClass, name);
244         }
245         return lib;
246     }
247 
248     // Called at the end of AOTCache assembly phase.
249     public void clear() {
250         libraries.clear();
251     }
252 
253     private NativeLibrary findFromPaths(String[] paths, Class<?> fromClass, String name) {
254         for (String path : paths) {
255             File libfile = new File(path, System.mapLibraryName(name));
256             NativeLibrary nl = loadLibrary(fromClass, libfile);
257             if (nl != null) {
258                 return nl;
259             }
260             libfile = ClassLoaderHelper.mapAlternativeName(libfile);
261             if (libfile != null) {
262                 nl = loadLibrary(fromClass, libfile);
263                 if (nl != null) {
264                     return nl;
265                 }
266             }
267         }
268         return null;
269     }
270 
271     /**
272      * NativeLibraryImpl denotes a loaded native library instance.

363         final String name;
364         final long handle;
365         final boolean isBuiltin;
366 
367         Unloader(String name, long handle, boolean isBuiltin) {
368             if (handle == 0) {
369                 throw new IllegalArgumentException(
370                         "Invalid handle for native library " + name);
371             }
372 
373             this.name = name;
374             this.handle = handle;
375             this.isBuiltin = isBuiltin;
376         }
377 
378         @Override
379         public void run() {
380             acquireNativeLibraryLock(name);
381             try {
382                 /* remove the native library name */
383                 if (!Holder.loadedLibraryNames.remove(name)) {
384                     throw new IllegalStateException(name + " has already been unloaded");
385                 }
386                 NativeLibraryContext.push(UNLOADER);
387                 try {
388                     unload(name, isBuiltin, handle);
389                 } finally {
390                     NativeLibraryContext.pop();
391                 }
392             } finally {
393                 releaseNativeLibraryLock(name);
394             }
395         }
396     }
397 
398     /*
399      * Holds system and user library paths derived from the
400      * {@code java.library.path} and {@code sun.boot.library.path} system
401      * properties. The system properties are eagerly read at bootstrap, then
402      * lazily parsed on first use to avoid initialization ordering issues.
403      */
404     static class LibraryPaths {
405         // The paths searched for libraries
406         static final String[] SYS_PATHS = ClassLoaderHelper.parsePath(StaticProperty.sunBootLibraryPath());
407         static final String[] USER_PATHS = ClassLoaderHelper.parsePath(StaticProperty.javaLibraryPath());
408     }
409 
410     // Holder has the fields that need to be initialized during JVM bootstrap even if
411     // the outer is aot-initialized.
412     static class Holder {
413         // All native libraries we've loaded.
414         private static final Set<String> loadedLibraryNames =
415             ConcurrentHashMap.newKeySet();
416     }
417 
418     // reentrant lock class that allows exact counting (with external synchronization)
419     @SuppressWarnings("serial")
420     private static final class CountedLock extends ReentrantLock {
421 
422         private int counter = 0;
423 
424         public void increment() {
425             if (counter == Integer.MAX_VALUE) {
426                 // prevent overflow
427                 throw new Error("Maximum lock count exceeded");
428             }
429             ++counter;
430         }
431 
432         public void decrement() {
433             --counter;
434         }
435 
436         public int getCounter() {
< prev index next >