From e9b82ce41c5da5c5e453d9398d3cef1312f22ec4 Mon Sep 17 00:00:00 2001 From: Samuel Audet Date: Mon, 22 Jan 2024 21:06:22 +0900 Subject: [PATCH] * Move native `Loader` methods to `Helper` class to avoid deadlocks (issue #737) --- CHANGELOG.md | 1 + .../java/org/bytedeco/javacpp/Loader.java | 96 ++++++++++++------- .../org/bytedeco/javacpp/tools/Generator.java | 3 +- 3 files changed, 65 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9de5b88a..736b5da49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ + * Move native `Loader` methods to `Helper` class to avoid deadlocks ([issue #737](https://github.com/bytedeco/javacpp/issues/737)) * Fix `Parser` failing to pick up `Info` for constructors with template arguments ([pull #739](https://github.com/bytedeco/javacpp/pull/739)) * Fix `MoveAdapter` and `UniquePtrAdapter` causing double free on function calls ([pull #738](https://github.com/bytedeco/javacpp/pull/738)) * Fix `Parser` handling of `template` specialization and their `friend` declarations ([pull #733](https://github.com/bytedeco/javacpp/pull/733)) diff --git a/src/main/java/org/bytedeco/javacpp/Loader.java b/src/main/java/org/bytedeco/javacpp/Loader.java index 819933d58..742063ebd 100644 --- a/src/main/java/org/bytedeco/javacpp/Loader.java +++ b/src/main/java/org/bytedeco/javacpp/Loader.java @@ -1968,16 +1968,6 @@ public static String createLibraryLink(String filename, ClassProperties properti static WeakHashMap,HashMap> memberOffsets = new WeakHashMap,HashMap>(); - static { - try { - Loader.load(); - } catch (Throwable t) { - if (logger.isDebugEnabled()) { - logger.debug("Could not load Loader: " + t); - } - } - } - /** * Called by native libraries to put {@code offsetof()} and {@code sizeof()} values in {@link #memberOffsets}. * Tries to load the Class object for typeName using the {@link ClassLoader} of the Loader. @@ -2044,37 +2034,75 @@ public static int sizeof(Class type) { return offsetof(type, "sizeof"); } + public static class Helper { + static { + try { + Loader.load(); + } catch (Throwable t) { + if (logger.isDebugEnabled()) { + logger.debug("Could not load Loader.Helper: " + t); + } + } + } + + /** Returns the number of processors configured according to the operating system, or 0 if unknown. + * This value can be greater than {@link Runtime#availableProcessors()} and {@link #totalCores()}. */ + @Name("JavaCPP_totalProcessors") public static native int totalProcessors(); + + /** Returns the number of CPU cores usable according to the operating system, or 0 if unknown. + * For SMT-capable systems, this value may be less than {@link #totalProcessors()}. */ + @Name("JavaCPP_totalCores") public static native int totalCores(); + + /** Returns the number of CPU chips installed according to the operating system, or 0 if unknown. + * For multi-core processors, this value may be less than {@link #totalCores()}. */ + @Name("JavaCPP_totalChips") public static native int totalChips(); + + /** Returns the address found under the given name in the "dynamic symbol tables" (Linux, Mac OS X, etc) + * or the "export tables" (Windows) of all libraries loaded, or null if not found. */ + @Name("JavaCPP_addressof") public static native Pointer addressof(String symbol); + + /** Loads all symbols from a library globally, that is {@code dlopen(filename, RTLD_LAZY | RTLD_GLOBAL)}, + * or simply by default with {@code LoadLibrary(filename)} on Windows. If the library name passed to + * one of the other load functions in this class ends with "!", this function will get called on them. */ + @Name("JavaCPP_loadGlobal") @Raw(withEnv = true) public static native void loadGlobal(String filename); + + /** Returns the JavaVM JNI object, as required by some APIs for initialization. */ + @Name("JavaCPP_getJavaVM") public static native @Cast("JavaVM*") Pointer getJavaVM(); + + /** Returns a JNI global reference stored in a Pointer for the given Object. */ + @Name("JavaCPP_newGlobalRef") public static native @Cast("jobject") Pointer newGlobalRef(@Raw(withEnv = true) Object object); + + /** Returns an Object from the JNI global reference stored in the Pointer. */ + @Name("JavaCPP_accessGlobalRef") @Raw(withEnv = true) public static native Object accessGlobalRef(@Cast("jobject") Pointer globalRef); + + /** Deletes the JNI global reference stored in the Pointer. */ + @Name("JavaCPP_deleteGlobalRef") @Raw(withEnv = true) public static native void deleteGlobalRef(@Cast("jobject") Pointer globalRef); + } - /** Returns the number of processors configured according to the operating system, or 0 if unknown. - * This value can be greater than {@link Runtime#availableProcessors()} and {@link #totalCores()}. */ - @Name("JavaCPP_totalProcessors") public static native int totalProcessors(); + /** Returns {@link Helper#totalProcessors()}. */ + public static int totalProcessors() { return Helper.totalProcessors(); } - /** Returns the number of CPU cores usable according to the operating system, or 0 if unknown. - * For SMT-capable systems, this value may be less than {@link #totalProcessors()}. */ - @Name("JavaCPP_totalCores") public static native int totalCores(); + /** Returns {@link Helper#totalCores()}. */ + public static int totalCores() { return Helper.totalCores(); } - /** Returns the number of CPU chips installed according to the operating system, or 0 if unknown. - * For multi-core processors, this value may be less than {@link #totalCores()}. */ - @Name("JavaCPP_totalChips") public static native int totalChips(); + /** Returns {@link Helper#totalChips()}. */ + public static int totalChips() { return Helper.totalChips(); } - /** Returns the address found under the given name in the "dynamic symbol tables" (Linux, Mac OS X, etc) - * or the "export tables" (Windows) of all libraries loaded, or null if not found. */ - @Name("JavaCPP_addressof") public static native Pointer addressof(String symbol); + /** Returns {@link Helper#addressof(String)}. */ + public static Pointer addressof(String symbol) { return Helper.addressof(symbol); } - /** Loads all symbols from a library globally, that is {@code dlopen(filename, RTLD_LAZY | RTLD_GLOBAL)}, - * or simply by default with {@code LoadLibrary(filename)} on Windows. If the library name passed to - * one of the other load functions in this class ends with "!", this function will get called on them. */ - @Name("JavaCPP_loadGlobal") @Raw(withEnv = true) public static native void loadGlobal(String filename); + /** Calls {@link Helper#loadGlobal(String)}. */ + public static void loadGlobal(String filename) { Helper.loadGlobal(filename); } - /** Returns the JavaVM JNI object, as required by some APIs for initialization. */ - @Name("JavaCPP_getJavaVM") public static native @Cast("JavaVM*") Pointer getJavaVM(); + /** Returns {@link Helper#getJavaVM()}. */ + public static Pointer getJavaVM() { return Helper.getJavaVM(); } - /** Returns a JNI global reference stored in a Pointer for the given Object. */ - @Name("JavaCPP_newGlobalRef") public static native @Cast("jobject") Pointer newGlobalRef(@Raw(withEnv = true) Object object); + /** Returns {@link Helper#newGlobalRef(Object)}. */ + public static Pointer newGlobalRef(Object object) { return Helper.newGlobalRef(object); } - /** Returns an Object from the JNI global reference stored in the Pointer. */ - @Name("JavaCPP_accessGlobalRef") @Raw(withEnv = true) public static native Object accessGlobalRef(@Cast("jobject") Pointer globalRef); + /** Returns {@link Helper#accessGlobalRef(Pointer)}. */ + public static Object accessGlobalRef(Pointer globalRef) { return Helper.accessGlobalRef(globalRef); } - /** Deletes the JNI global reference stored in the Pointer. */ - @Name("JavaCPP_deleteGlobalRef") @Raw(withEnv = true) public static native void deleteGlobalRef(@Cast("jobject") Pointer globalRef); + /** Calls {@link Helper#deleteGlobalRef(Pointer)}. */ + public static void deleteGlobalRef(Pointer globalRef) { Helper.deleteGlobalRef(globalRef); } } diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index 08211c90e..5b14ca017 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -154,7 +154,7 @@ static enum IntEnum { INT; int value; } static enum LongEnum { LONG; long value; } static final String JNI_VERSION = "JNI_VERSION_1_6"; static final List baseClasses = Arrays.asList(new Class[] { - Loader.class, + Loader.Helper.class, Pointer.class, //FunctionPointer.class, BytePointer.class, @@ -2065,6 +2065,7 @@ boolean methods(Class cls) { Set memberList = members.get(cls); if (!cls.isAnnotationPresent(Opaque.class) && cls != Loader.class && !FunctionPointer.class.isAssignableFrom(cls) + && cls.getEnclosingClass() != Loader.class && cls.getEnclosingClass() != Pointer.class) { if (memberList == null) { members.put(cls, memberList = new LinkedHashSet());