Skip to content

Commit

Permalink
* Move native Loader methods to Helper class to avoid deadlocks …
Browse files Browse the repository at this point in the history
…(issue #737)
  • Loading branch information
saudet committed Jan 22, 2024
1 parent 26eb486 commit e9b82ce
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 35 deletions.
1 change: 1 addition & 0 deletions 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))
Expand Down
96 changes: 62 additions & 34 deletions src/main/java/org/bytedeco/javacpp/Loader.java
Expand Up @@ -1968,16 +1968,6 @@ public static String createLibraryLink(String filename, ClassProperties properti
static WeakHashMap<Class<? extends Pointer>,HashMap<String,Integer>> memberOffsets =
new WeakHashMap<Class<? extends Pointer>,HashMap<String,Integer>>();

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.
Expand Down Expand Up @@ -2044,37 +2034,75 @@ public static int sizeof(Class<? extends Pointer> 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); }
}
3 changes: 2 additions & 1 deletion src/main/java/org/bytedeco/javacpp/tools/Generator.java
Expand Up @@ -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<Class> baseClasses = Arrays.asList(new Class[] {
Loader.class,
Loader.Helper.class,
Pointer.class,
//FunctionPointer.class,
BytePointer.class,
Expand Down Expand Up @@ -2065,6 +2065,7 @@ boolean methods(Class<?> cls) {
Set<String> 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<String>());
Expand Down

0 comments on commit e9b82ce

Please sign in to comment.