< 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

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

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





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

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



400             ConcurrentHashMap.newKeySet();

401 
402     // reentrant lock class that allows exact counting (with external synchronization)
403     @SuppressWarnings("serial")
404     private static final class CountedLock extends ReentrantLock {
405 
406         private int counter = 0;
407 
408         public void increment() {
409             if (counter == Integer.MAX_VALUE) {
410                 // prevent overflow
411                 throw new Error("Maximum lock count exceeded");
412             }
413             ++counter;
414         }
415 
416         public void decrement() {
417             --counter;
418         }
419 
420         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

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

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

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