diff options
author | Sven Gothel <[email protected]> | 2021-01-25 01:28:36 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2021-01-25 01:28:36 +0100 |
commit | b371af6d83e0fb94cba02ec6c2837bf58c2eea39 (patch) | |
tree | 48999c7e269409ebe389e5d5e72ca141d8b9eea7 /java_jni | |
parent | 1ba932716f2d382af56bf8ea69a57666e2c835d6 (diff) |
Java import and modularization: jaulib_base, jaulib_jni, jaulib_net, jaulib_pkg (WIP)
Diffstat (limited to 'java_jni')
24 files changed, 3011 insertions, 0 deletions
diff --git a/java_jni/CMakeLists.txt b/java_jni/CMakeLists.txt new file mode 100644 index 0000000..e758520 --- /dev/null +++ b/java_jni/CMakeLists.txt @@ -0,0 +1,21 @@ +# java/CMakeLists.txt + +set(CMAKE_JNI_TARGET TRUE) +file(GLOB_RECURSE JAVA_SOURCES "*.java") +add_jar(jaulib_jni_jar + ${JAVA_SOURCES} + INCLUDE_JARS jaulib_base_jar + MANIFEST ${CMAKE_CURRENT_BINARY_DIR}/manifest.txt + OUTPUT_NAME jaulib_jni + GENERATE_NATIVE_HEADERS jaulib_jni_javah + DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/jaulib_jni_jar.dir/jni" +) +add_dependencies(jaulib_jni_jar jaulib_base_jar) +#add_dependencies(jaulib_net_jar jaulib_base_jar jaulib_jni_jar) +#add_dependencies(jaulib_pkg_jar jaulib_base_jar jaulib_jni_jar jaulib_net_jar) + +set(JNI_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/jaulib_jni_jar.dir/jni") +install (FILES ${CMAKE_CURRENT_BINARY_DIR}/jaulib_jni.jar DESTINATION ${CMAKE_INSTALL_LIBDIR}/../lib/java) + +add_subdirectory (jni) + diff --git a/java_jni/jau/sys/MachineDataInfoRuntime.java b/java_jni/jau/sys/MachineDataInfoRuntime.java new file mode 100644 index 0000000..d024bf6 --- /dev/null +++ b/java_jni/jau/sys/MachineDataInfoRuntime.java @@ -0,0 +1,155 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2021 Gothel Software e.K. + * Copyright (c) 2010 Gothel Software e.K. + * Copyright (c) 2010 JogAmp Community. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package jau.sys; + +import org.jau.sys.MachineDataInfo; +import org.jau.sys.MachineDataInfo.StaticConfig; +import org.jau.sys.PlatformProps; +import org.jau.sys.PlatformTypes; + +/** + * Runtime operations of {@link MachineDataInfo}. + */ +public class MachineDataInfoRuntime { + + static volatile boolean initialized = false; + static volatile MachineDataInfo runtimeMD = null; + static volatile MachineDataInfo.StaticConfig staticMD = null; + + public static void initialize() { + if( !initialized ) { + synchronized(MachineDataInfo.class) { // volatile dbl-checked-locking OK + if( !initialized ) { + MachineDataInfo.StaticConfig.validateUniqueMachineDataInfo(); + + final MachineDataInfo runtimeMD = getRuntimeImpl(); + final MachineDataInfo.StaticConfig staticMD = MachineDataInfo.StaticConfig.findCompatible(runtimeMD); + if( null == staticMD ) { + throw new RuntimeException("No compatible MachineDataInfo.StaticConfig for runtime:"+PlatformProps.NEWLINE+runtimeMD); + } + if( !staticMD.md.compatible(runtimeMD) ) { + throw new RuntimeException("Incompatible MachineDataInfo:"+PlatformProps.NEWLINE+ + " Static "+staticMD+PlatformProps.NEWLINE+ + " Runtime "+runtimeMD); + } + MachineDataInfoRuntime.runtimeMD = runtimeMD; + MachineDataInfoRuntime.staticMD = staticMD; + initialized=true; + if( PlatformProps.DEBUG ) { + System.err.println("MachineDataInfoRuntime.initialize():"+PlatformProps.NEWLINE+ + " Static "+staticMD+PlatformProps.NEWLINE+ + " Runtime "+runtimeMD); + } + return; + } + } + } + throw new InternalError("Already initialized"); + } + /** + * The static {@link MachineDataInfo} is utilized for high performance + * precompiled size, offset, etc table lookup within generated structures + * using the {@link MachineDataInfo.StaticConfig} index. + */ + public static MachineDataInfo.StaticConfig getStatic() { + if(!initialized) { + synchronized(MachineDataInfo.class) { // volatile dbl-checked-locking OK + if(!initialized) { + throw new InternalError("Not set"); + } + } + } + return staticMD; + } + public static MachineDataInfo getRuntime() { + if(!initialized) { + synchronized(MachineDataInfo.class) { // volatile dbl-checked-locking OK + if(!initialized) { + throw new InternalError("Not set"); + } + } + } + return runtimeMD; + } + + private static MachineDataInfo getRuntimeImpl() { + try { + PlatformProps.initSingleton(); + } catch (final Throwable err) { + return null; + } + + final int pointerSizeInBytes = getPointerSizeInBytesImpl(); + switch(pointerSizeInBytes) { + case 4: + case 8: + break; + default: + throw new RuntimeException("Unsupported pointer size "+pointerSizeInBytes+"bytes, please implement."); + } + + final long pageSizeL = getPageSizeInBytesImpl(); + if(Integer.MAX_VALUE < pageSizeL) { + throw new InternalError("PageSize exceeds integer value: " + pageSizeL); + } + + // size: int, long, float, double, pointer, pageSize + // alignment: int8, int16, int32, int64, int, long, float, double, pointer + return new MachineDataInfo( + true /* runtime validated */, + + getSizeOfIntImpl(), getSizeOfLongImpl(), + getSizeOfFloatImpl(), getSizeOfDoubleImpl(), getSizeOfLongDoubleImpl(), + pointerSizeInBytes, (int)pageSizeL, + + getAlignmentInt8Impl(), getAlignmentInt16Impl(), getAlignmentInt32Impl(), getAlignmentInt64Impl(), + getAlignmentIntImpl(), getAlignmentLongImpl(), + getAlignmentFloatImpl(), getAlignmentDoubleImpl(), getAlignmentLongDoubleImpl(), + getAlignmentPointerImpl()); + } + + private static native int getPointerSizeInBytesImpl(); + private static native long getPageSizeInBytesImpl(); + + private static native int getAlignmentInt8Impl(); + private static native int getAlignmentInt16Impl(); + private static native int getAlignmentInt32Impl(); + private static native int getAlignmentInt64Impl(); + private static native int getAlignmentIntImpl(); + private static native int getAlignmentLongImpl(); + private static native int getAlignmentPointerImpl(); + private static native int getAlignmentFloatImpl(); + private static native int getAlignmentDoubleImpl(); + private static native int getAlignmentLongDoubleImpl(); + private static native int getSizeOfIntImpl(); + private static native int getSizeOfLongImpl(); + private static native int getSizeOfPointerImpl(); + private static native int getSizeOfFloatImpl(); + private static native int getSizeOfDoubleImpl(); + private static native int getSizeOfLongDoubleImpl(); +} + diff --git a/java_jni/jau/sys/dl/BionicDynamicLinker32bitImpl.java b/java_jni/jau/sys/dl/BionicDynamicLinker32bitImpl.java new file mode 100644 index 0000000..9aa8c02 --- /dev/null +++ b/java_jni/jau/sys/dl/BionicDynamicLinker32bitImpl.java @@ -0,0 +1,61 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2021 Gothel Software e.K. + * Copyright (c) 2013 Gothel Software e.K. + * Copyright (c) 2013 JogAmp Community. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package jau.sys.dl; + +/** + * Bionic 32bit specialization of {@link UnixDynamicLinkerImpl} + * utilizing Bionic's non POSIX flags and mode values. + * <p> + * Bionic is used on Android. + * </p> + */ +public final class BionicDynamicLinker32bitImpl extends UnixDynamicLinkerImpl { + + // static final int RTLD_NOW = 0x00000; + private static final int RTLD_LAZY = 0x00001; + + private static final int RTLD_LOCAL = 0x00000; + private static final int RTLD_GLOBAL = 0x00002; + // static final int RTLD_NOLOAD = 0x00004; + + private static final long RTLD_DEFAULT = 0xffffffffL; + // static final long RTLD_NEXT = 0xfffffffeL; + + @Override + protected final long openLibraryLocalImpl(final String pathname) throws SecurityException { + return dlopen(pathname, RTLD_LAZY | RTLD_LOCAL); + } + + @Override + protected final long openLibraryGlobalImpl(final String pathname) throws SecurityException { + return dlopen(pathname, RTLD_LAZY | RTLD_GLOBAL); + } + + @Override + protected final long lookupSymbolGlobalImpl(final String symbolName) throws SecurityException { + return dlsym(RTLD_DEFAULT, symbolName); + } +} diff --git a/java_jni/jau/sys/dl/BionicDynamicLinker64BitImpl.java b/java_jni/jau/sys/dl/BionicDynamicLinker64BitImpl.java new file mode 100644 index 0000000..bfbc7f0 --- /dev/null +++ b/java_jni/jau/sys/dl/BionicDynamicLinker64BitImpl.java @@ -0,0 +1,61 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2021 Gothel Software e.K. + * Copyright (c) 2015 Gothel Software e.K. + * Copyright (c) 2015 JogAmp Community. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package jau.sys.dl; + +/** + * Bionic 64bit specialization of {@link UnixDynamicLinkerImpl} + * utilizing Bionic's non POSIX flags and mode values. + * <p> + * Bionic is used on Android. + * </p> + */ +public final class BionicDynamicLinker64BitImpl extends UnixDynamicLinkerImpl { + // static final int RTLD_NOW = 0x00002; + private static final int RTLD_LAZY = 0x00001; + + private static final int RTLD_LOCAL = 0x00000; + private static final int RTLD_GLOBAL = 0x00100; + // static final int RTLD_NOLOAD = 0x00004; + + private static final long RTLD_DEFAULT = 0x00000000L; + // static final long RTLD_NEXT = -1L; + + @Override + protected final long openLibraryLocalImpl(final String pathname) throws SecurityException { + return dlopen(pathname, RTLD_LAZY | RTLD_LOCAL); + } + + @Override + protected final long openLibraryGlobalImpl(final String pathname) throws SecurityException { + return dlopen(pathname, RTLD_LAZY | RTLD_GLOBAL); + } + + @Override + protected final long lookupSymbolGlobalImpl(final String symbolName) throws SecurityException { + return dlsym(RTLD_DEFAULT, symbolName); + } + +} diff --git a/java_jni/jau/sys/dl/DynamicLinkerImpl.java b/java_jni/jau/sys/dl/DynamicLinkerImpl.java new file mode 100644 index 0000000..407666e --- /dev/null +++ b/java_jni/jau/sys/dl/DynamicLinkerImpl.java @@ -0,0 +1,215 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2021 Gothel Software e.K. + * Copyright (c) 2013 Gothel Software e.K. + * Copyright (c) 2013 JogAmp Community. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package jau.sys.dl; + +import java.util.HashMap; + +import org.jau.sec.SecurityUtil; +import org.jau.sys.dl.DynamicLinker; + +/* pp */ abstract class DynamicLinkerImpl implements DynamicLinker { + + // + // Package private scope of class w/ protected native code access + // and sealed jogamp.common.* package definition + // ensuring no abuse via subclassing. + // + + private final Object secSync = new Object(); + private boolean allLinkPermissionGranted = false; + + /** + * @throws SecurityException if user is not granted global access + */ + @Override +public final void claimAllLinkPermission() throws SecurityException { + synchronized( secSync ) { + allLinkPermissionGranted = true; + } + } + + /** + * @throws SecurityException if user is not granted global access + */ + @Override +public final void releaseAllLinkPermission() throws SecurityException { + synchronized( secSync ) { + allLinkPermissionGranted = false; + } + } + + private final void checkLinkPermission(final String pathname) throws SecurityException { + synchronized( secSync ) { + if( !allLinkPermissionGranted ) { + SecurityUtil.checkLinkPermission(pathname); + } + } + } + private final void checkLinkPermission(final long libraryHandle) throws SecurityException { + synchronized( secSync ) { + if( !allLinkPermissionGranted ) { + final LibRef libRef = getLibRef( libraryHandle ); + if( null == libRef ) { + throw new IllegalArgumentException("Library handle 0x"+Long.toHexString(libraryHandle)+" unknown."); + } + SecurityUtil.checkLinkPermission(libRef.getName()); + } + } + } + + private final void checkAllLinkPermission() throws SecurityException { + synchronized( secSync ) { + if( !allLinkPermissionGranted ) { + SecurityUtil.checkAllLinkPermission(); + } + } + } + + @Override + public final long openLibraryGlobal(final String pathname, final boolean debug) throws SecurityException { + checkLinkPermission(pathname); + final long handle = openLibraryGlobalImpl(pathname); + if( 0 != handle ) { + final LibRef libRef = incrLibRefCount(handle, pathname); + if( DEBUG || debug ) { + System.err.println("DynamicLinkerImpl.openLibraryGlobal \""+pathname+"\": 0x"+Long.toHexString(handle)+" -> "+libRef+")"); + } + } else if ( DEBUG || debug ) { + System.err.println("DynamicLinkerImpl.openLibraryGlobal \""+pathname+"\" failed, error: "+getLastError()); + } + return handle; + } + protected abstract long openLibraryGlobalImpl(final String pathname) throws SecurityException; + + @Override + public final long openLibraryLocal(final String pathname, final boolean debug) throws SecurityException { + checkLinkPermission(pathname); + final long handle = openLibraryLocalImpl(pathname); + if( 0 != handle ) { + final LibRef libRef = incrLibRefCount(handle, pathname); + if( DEBUG || debug ) { + System.err.println("DynamicLinkerImpl.openLibraryLocal \""+pathname+"\": 0x"+Long.toHexString(handle)+" -> "+libRef+")"); + } + } else if ( DEBUG || debug ) { + System.err.println("DynamicLinkerImpl.openLibraryLocal \""+pathname+"\" failed, error: "+getLastError()); + } + return handle; + } + protected abstract long openLibraryLocalImpl(final String pathname) throws SecurityException; + + @Override + public final long lookupSymbolGlobal(final String symbolName) throws SecurityException { + checkAllLinkPermission(); + final long addr = lookupSymbolGlobalImpl(symbolName); + if(DEBUG_LOOKUP) { + System.err.println("DynamicLinkerImpl.lookupSymbolGlobal("+symbolName+") -> 0x"+Long.toHexString(addr)); + } + return addr; + } + protected abstract long lookupSymbolGlobalImpl(final String symbolName) throws SecurityException; + + @Override + public final long lookupSymbol(final long libraryHandle, final String symbolName) throws SecurityException, IllegalArgumentException { + checkLinkPermission(libraryHandle); + final long addr = lookupSymbolLocalImpl(libraryHandle, symbolName); + if(DEBUG_LOOKUP) { + System.err.println("DynamicLinkerImpl.lookupSymbol(0x"+Long.toHexString(libraryHandle)+", "+symbolName+") -> 0x"+Long.toHexString(addr)); + } + return addr; + } + protected abstract long lookupSymbolLocalImpl(final long libraryHandle, final String symbolName) throws SecurityException; + + @Override + public final void closeLibrary(final long libraryHandle, final boolean debug) throws SecurityException, IllegalArgumentException { + final LibRef libRef = decrLibRefCount( libraryHandle ); + if( null != libRef ) { + checkLinkPermission(libRef.getName()); + } // else null libRef is OK for global lookup + if( DEBUG || debug ) { + System.err.println("DynamicLinkerImpl.closeLibrary(0x"+Long.toHexString(libraryHandle)+" -> "+libRef+")"); + } + if( 0 != libraryHandle ) { + closeLibraryImpl(libraryHandle); + } + } + protected abstract void closeLibraryImpl(final long libraryHandle) throws SecurityException; + + private static final HashMap<Long,Object> libHandle2Name = new HashMap<Long,Object>( 16 /* initialCapacity */ ); + + static final class LibRef { + LibRef(final String name) { + this.name = name; + this.refCount = 1; + } + final int incrRefCount() { return ++refCount; } + final int decrRefCount() { return --refCount; } + final int getRefCount() { return refCount; } + + final String getName() { return name; } + @Override + public final String toString() { return "LibRef["+name+", refCount "+refCount+"]"; } + + private final String name; + private int refCount; + } + + private final LibRef getLibRef(final long handle) { + synchronized( libHandle2Name ) { + return (LibRef) libHandle2Name.get(handle); + } + } + + private final LibRef incrLibRefCount(final long handle, final String libName) { + synchronized( libHandle2Name ) { + LibRef libRef = getLibRef(handle); + if( null == libRef ) { + libRef = new LibRef(libName); + libHandle2Name.put(handle, libRef); + } else { + libRef.incrRefCount(); + } + if(DEBUG) { + System.err.println("DynamicLinkerImpl.incrLibRefCount 0x"+Long.toHexString(handle)+ " -> "+libRef+", libs loaded "+libHandle2Name.size()); + } + return libRef; + } + } + + private final LibRef decrLibRefCount(final long handle) { + synchronized( libHandle2Name ) { + final LibRef libRef = getLibRef(handle); + if( null != libRef ) { + if( 0 == libRef.decrRefCount() ) { + libHandle2Name.remove(handle); + } + } + if(DEBUG) { + System.err.println("DynamicLinkerImpl.decrLibRefCount 0x"+Long.toHexString(handle)+ " -> "+libRef+", libs loaded "+libHandle2Name.size()); + } + return libRef; + } + } +} diff --git a/java_jni/jau/sys/dl/MacOSXDynamicLinkerImpl.java b/java_jni/jau/sys/dl/MacOSXDynamicLinkerImpl.java new file mode 100644 index 0000000..68c70da --- /dev/null +++ b/java_jni/jau/sys/dl/MacOSXDynamicLinkerImpl.java @@ -0,0 +1,57 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2021 Gothel Software e.K. + * Copyright (c) 2013 Gothel Software e.K. + * Copyright (c) 2013 JogAmp Community. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package jau.sys.dl; + +/** + * Mac OS X specialization of {@link UnixDynamicLinkerImpl} + * utilizing OS X 's non POSIX flags and mode values. + */ +public final class MacOSXDynamicLinkerImpl extends UnixDynamicLinkerImpl { + + private static final long RTLD_DEFAULT = -2L; + // static final long RTLD_NEXT = -1L; + + private static final int RTLD_LAZY = 0x00001; + // static final int RTLD_NOW = 0x00002; + private static final int RTLD_LOCAL = 0x00004; + private static final int RTLD_GLOBAL = 0x00008; + + @Override + protected final long openLibraryLocalImpl(final String pathname) throws SecurityException { + return dlopen(pathname, RTLD_LAZY | RTLD_LOCAL); + } + + @Override + protected final long openLibraryGlobalImpl(final String pathname) throws SecurityException { + return dlopen(pathname, RTLD_LAZY | RTLD_GLOBAL); + } + + @Override + protected final long lookupSymbolGlobalImpl(final String symbolName) throws SecurityException { + return dlsym(RTLD_DEFAULT, symbolName); + } + +} diff --git a/java_jni/jau/sys/dl/PosixDynamicLinkerImpl.java b/java_jni/jau/sys/dl/PosixDynamicLinkerImpl.java new file mode 100644 index 0000000..438fa9a --- /dev/null +++ b/java_jni/jau/sys/dl/PosixDynamicLinkerImpl.java @@ -0,0 +1,52 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2021 Gothel Software e.K. + * Copyright (c) 2013 Gothel Software e.K. + * Copyright (c) 2013 JogAmp Community. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package jau.sys.dl; + +public final class PosixDynamicLinkerImpl extends UnixDynamicLinkerImpl { + + private static final long RTLD_DEFAULT = 0; + // private static final long RTLD_NEXT = -1L; + + private static final int RTLD_LAZY = 0x00001; + // private static final int RTLD_NOW = 0x00002; + private static final int RTLD_LOCAL = 0x00000; + private static final int RTLD_GLOBAL = 0x00100; + + @Override + protected final long openLibraryLocalImpl(final String pathname) throws SecurityException { + return dlopen(pathname, RTLD_LAZY | RTLD_LOCAL); + } + + @Override + protected final long openLibraryGlobalImpl(final String pathname) throws SecurityException { + return dlopen(pathname, RTLD_LAZY | RTLD_GLOBAL); + } + + @Override + protected final long lookupSymbolGlobalImpl(final String symbolName) throws SecurityException { + return dlsym(RTLD_DEFAULT, symbolName); + } +} diff --git a/java_jni/jau/sys/dl/UnixDynamicLinkerImpl.java b/java_jni/jau/sys/dl/UnixDynamicLinkerImpl.java new file mode 100644 index 0000000..fb25782 --- /dev/null +++ b/java_jni/jau/sys/dl/UnixDynamicLinkerImpl.java @@ -0,0 +1,64 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2021 Gothel Software e.K. + * Copyright (c) 2013 Gothel Software e.K. + * Copyright (c) 2013 JogAmp Community. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package jau.sys.dl; + +/* pp */ abstract class UnixDynamicLinkerImpl extends DynamicLinkerImpl { + + // + // Package private scope of class w/ protected native code access + // and sealed jogamp.common.* package definition + // ensuring no abuse via subclassing. + // + + /** Interface to C language function: <br> <code> int dlclose(void * ); </code> */ + protected static native int dlclose(long arg0); + + /** Interface to C language function: <br> <code> char * dlerror(void); </code> */ + protected static native java.lang.String dlerror(); + + /** Interface to C language function: <br> <code> void * dlopen(const char * , int); </code> */ + protected static native long dlopen(java.lang.String arg0, int arg1); + + /** Interface to C language function: <br> <code> void * dlsym(void * , const char * ); </code> */ + protected static native long dlsym(long arg0, java.lang.String arg1); + + @Override + protected final long lookupSymbolLocalImpl(final long libraryHandle, final String symbolName) throws SecurityException { + return 0 != libraryHandle ? dlsym(libraryHandle, symbolName) : 0; + } + + @Override + protected final void closeLibraryImpl(final long libraryHandle) throws SecurityException { + if( 0 != libraryHandle ) { + dlclose(libraryHandle); + } + } + + @Override + public final String getLastError() { + return dlerror(); + } +} diff --git a/java_jni/jau/sys/dl/WindowsDynamicLinkerImpl.java b/java_jni/jau/sys/dl/WindowsDynamicLinkerImpl.java new file mode 100644 index 0000000..9a4c8a5 --- /dev/null +++ b/java_jni/jau/sys/dl/WindowsDynamicLinkerImpl.java @@ -0,0 +1,92 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2021 Gothel Software e.K. + * Copyright (c) 2013 Gothel Software e.K. + * Copyright (c) 2013 JogAmp Community. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package jau.sys.dl; + +public final class WindowsDynamicLinkerImpl extends DynamicLinkerImpl { + + /** Interface to C language function: <br> <code> BOOL FreeLibrary(HANDLE hLibModule); </code> */ + private static native int FreeLibrary(long hLibModule); + + /** Interface to C language function: <br> <code> DWORD GetLastError(void); </code> */ + private static native int GetLastError(); + + /** Interface to C language function: <br> <code> PROC GetProcAddressA(HANDLE hModule, LPCSTR lpProcName); </code> */ + private static native long GetProcAddressA(long hModule, java.lang.String lpProcName); + + /** Interface to C language function: <br> <code> HANDLE LoadLibraryW(LPCWSTR lpLibFileName); </code> */ + private static native long LoadLibraryW(java.lang.String lpLibFileName); + + @Override + protected final long openLibraryLocalImpl(final String libraryName) throws SecurityException { + // How does that work under Windows ? + // Don't know .. so it's an alias to global, for the time being + return LoadLibraryW(libraryName); + } + + @Override + protected final long openLibraryGlobalImpl(final String libraryName) throws SecurityException { + return LoadLibraryW(libraryName); + } + + @Override + protected final long lookupSymbolGlobalImpl(final String symbolName) throws SecurityException { + if(DEBUG_LOOKUP) { + System.err.println("lookupSymbolGlobal: Not supported on Windows"); + } + // allow DynamicLibraryBundle to continue w/ local libs + return 0; + } + + private static final int symbolArgAlignment=4; // 4 byte alignment of each argument + private static final int symbolMaxArguments=12; // experience .. + + @Override + protected final long lookupSymbolLocalImpl(final long libraryHandle, final String symbolName) throws IllegalArgumentException { + String _symbolName = symbolName; + long addr = GetProcAddressA(libraryHandle, _symbolName); + if( 0 == addr ) { + // __stdcall hack: try some @nn decorations, + // the leading '_' must not be added (same with cdecl) + for(int arg=0; 0==addr && arg<=symbolMaxArguments; arg++) { + _symbolName = symbolName+"@"+(arg*symbolArgAlignment); + addr = GetProcAddressA(libraryHandle, _symbolName); + } + } + return addr; + } + + @Override + protected final void closeLibraryImpl(final long libraryHandle) throws IllegalArgumentException { + FreeLibrary(libraryHandle); + } + + @Override + public final String getLastError() { + final int err = GetLastError(); + return "Last error: 0x"+Integer.toHexString(err)+" ("+err+")"; + } + +} diff --git a/java_jni/jni/CMakeLists.txt b/java_jni/jni/CMakeLists.txt new file mode 100644 index 0000000..5a0065c --- /dev/null +++ b/java_jni/jni/CMakeLists.txt @@ -0,0 +1,42 @@ +find_package(JNI REQUIRED) + +set (jaulib_base_LIB_INCLUDE_DIRS + ${PROJECT_SOURCE_DIR}/include +) + +include_directories( + ${JNI_INCLUDE_DIRS} + ${jaulib_base_LIB_INCLUDE_DIRS} + ${JNI_HEADER_PATH} +) + +set (jaulib_jni_JNI_SRCS + ${PROJECT_SOURCE_DIR}/java_jni/jni/jni_mem.cxx + ${PROJECT_SOURCE_DIR}/java_jni/jni/helper_jni.cxx + ${PROJECT_SOURCE_DIR}/java_jni/jni/jau/JVM_JNI8.cxx + ${PROJECT_SOURCE_DIR}/java_jni/jni/jau/MachineDataInfoRuntime.cxx + ${PROJECT_SOURCE_DIR}/java_jni/jni/jau/Clock.cxx +) + +if(WIN32) + set (jaulib_jni_JNI_SRCS ${jaulib_jni_JNI_SRCS} ${PROJECT_SOURCE_DIR}/java_jni/jni/jau/WindowsDynamicLinkerImpl_JNI.cxx) +else() + set (jaulib_jni_JNI_SRCS ${jaulib_jni_JNI_SRCS} ${PROJECT_SOURCE_DIR}/java_jni/jni/jau/UnixDynamicLinkerImpl_JNI.cxx) +endif() + +set (CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed") + +add_library (jaulib_jni_jni SHARED ${jaulib_jni_JNI_SRCS}) +target_link_libraries(jaulib_jni_jni ${JNI_LIBRARIES} jaulib) + +set_target_properties( + jaulib_jni_jni + PROPERTIES + SOVERSION ${jaulib_VERSION_MAJOR} + VERSION ${jaulib_VERSION_STRING} +) + +install(TARGETS jaulib_jni_jni LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +add_dependencies(jaulib_jni_jni jaulib jaulib_base_jar jaulib_jni_jar) + diff --git a/java_jni/jni/helper_jni.cxx b/java_jni/jni/helper_jni.cxx new file mode 100644 index 0000000..e083f8b --- /dev/null +++ b/java_jni/jni/helper_jni.cxx @@ -0,0 +1,354 @@ +/* + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Author: Andrei Vasiliu <[email protected]> + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <jni.h> +#include <memory> +#include <stdexcept> +#include <vector> + +#include <jau/jni/helper_jni.hpp> + +using namespace jau; + +// +// C++ <-> java exceptions +// + +bool jau::java_exception_check(JNIEnv *env, const char* file, int line) +{ + jthrowable e = env->ExceptionOccurred(); + if( nullptr != e ) { +#if 1 + // ExceptionDescribe prints an exception and a backtrace of the stack to a system error-reporting channel, such as stderr. + // The pending exception is cleared as a side-effect of calling this function. This is a convenience routine provided for debugging. + env->ExceptionDescribe(); +#endif + env->ExceptionClear(); // just be sure, to have same side-effects + + jclass eClazz = search_class(env, e); + jmethodID toString = search_method(env, eClazz, "toString", "()Ljava/lang/String;", false); + jstring jmsg = (jstring) env->CallObjectMethod(e, toString); + std::string msg = from_jstring_to_string(env, jmsg); + fprintf(stderr, "Java exception occurred @ %s:%d and forward to Java: %s\n", file, line, msg.c_str()); fflush(stderr); + + env->Throw(e); // re-throw the java exception - java side! + return true; + } + return false; +} + +void jau::java_exception_check_and_throw(JNIEnv *env, const char* file, int line) +{ + jthrowable e = env->ExceptionOccurred(); + if( nullptr != e ) { + // ExceptionDescribe prints an exception and a backtrace of the stack to a system error-reporting channel, such as stderr. + // The pending exception is cleared as a side-effect of calling this function. This is a convenience routine provided for debugging. + env->ExceptionDescribe(); + env->ExceptionClear(); // just be sure, to have same side-effects + + jclass eClazz = search_class(env, e); + jmethodID toString = search_method(env, eClazz, "toString", "()Ljava/lang/String;", false); + jstring jmsg = (jstring) env->CallObjectMethod(e, toString); + std::string msg = from_jstring_to_string(env, jmsg); + fprintf(stderr, "Java exception occurred @ %s:%d and forward to Native: %s\n", file, line, msg.c_str()); fflush(stderr); + + throw jau::RuntimeException("Java exception occurred @ %s : %d: "+msg, file, line); + } +} + +void jau::print_native_caught_exception_fwd2java(const std::exception &e, const char* file, int line) { + fprintf(stderr, "Native exception caught @ %s:%d and forward to Java: %s\n", file, line, e.what()); fflush(stderr); +} +void jau::print_native_caught_exception_fwd2java(const std::string &msg, const char* file, int line) { + fprintf(stderr, "Native exception caught @ %s:%d and forward to Java: %s\n", file, line, msg.c_str()); fflush(stderr); +} +void jau::print_native_caught_exception_fwd2java(const char * cmsg, const char* file, int line) { + fprintf(stderr, "Native exception caught @ %s:%d and forward to Java: %s\n", file, line, cmsg); fflush(stderr); +} + +void jau::raise_java_exception(JNIEnv *env, const std::exception &e, const char* file, int line) { + print_native_caught_exception_fwd2java(e, file, line); + env->ThrowNew(env->FindClass("java/lang/Error"), e.what()); +} +void jau::raise_java_exception(JNIEnv *env, const std::runtime_error &e, const char* file, int line) { + print_native_caught_exception_fwd2java(e, file, line); + env->ThrowNew(env->FindClass("java/lang/RuntimeException"), e.what()); +} +void jau::raise_java_exception(JNIEnv *env, const jau::RuntimeException &e, const char* file, int line) { + print_native_caught_exception_fwd2java(e, file, line); + env->ThrowNew(env->FindClass("java/lang/RuntimeException"), e.what()); +} +void jau::raise_java_exception(JNIEnv *env, const jau::InternalError &e, const char* file, int line) { + print_native_caught_exception_fwd2java(e, file, line); + env->ThrowNew(env->FindClass("java/lang/InternalError"), e.what()); +} +void jau::raise_java_exception(JNIEnv *env, const jau::NullPointerException &e, const char* file, int line) { + print_native_caught_exception_fwd2java(e, file, line); + env->ThrowNew(env->FindClass("java/lang/NullPointerException"), e.what()); +} +void jau::raise_java_exception(JNIEnv *env, const jau::IllegalArgumentException &e, const char* file, int line) { + print_native_caught_exception_fwd2java(e, file, line); + env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"), e.what()); +} +void jau::raise_java_exception(JNIEnv *env, const std::invalid_argument &e, const char* file, int line) { + print_native_caught_exception_fwd2java(e, file, line); + env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"), e.what()); +} +void jau::raise_java_exception(JNIEnv *env, const jau::IllegalStateException &e, const char* file, int line) { + print_native_caught_exception_fwd2java(e, file, line); + env->ThrowNew(env->FindClass("java/lang/IllegalStateException"), e.what()); +} +void jau::raise_java_exception(JNIEnv *env, const jau::UnsupportedOperationException &e, const char* file, int line) { + print_native_caught_exception_fwd2java(e, file, line); + env->ThrowNew(env->FindClass("java/lang/UnsupportedOperationException"), e.what()); +} +void jau::raise_java_exception(JNIEnv *env, const jau::IndexOutOfBoundsException &e, const char* file, int line) { + print_native_caught_exception_fwd2java(e, file, line); + env->ThrowNew(env->FindClass("java/lang/IndexOutOfBoundsException"), e.what()); +} +void jau::raise_java_exception(JNIEnv *env, const std::bad_alloc &e, const char* file, int line) { + print_native_caught_exception_fwd2java(e, file, line); + env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), e.what()); +} +void jau::raise_java_exception(JNIEnv *env, const jau::OutOfMemoryError &e, const char* file, int line) { + print_native_caught_exception_fwd2java(e, file, line); + env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), e.what()); +} + +static std::string _unknown_exception_type_msg("Unknown exception type"); + +void jau::rethrow_and_raise_java_exception_jauimpl(JNIEnv *env, const char* file, int line) { + // std::exception_ptr e = std::current_exception(); + try { + // std::rethrow_exception(e); + throw; // re-throw current exception + } catch (const std::bad_alloc &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const jau::OutOfMemoryError &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const jau::InternalError &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const jau::NullPointerException &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const jau::IllegalArgumentException &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const jau::IllegalStateException &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const jau::UnsupportedOperationException &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const jau::IndexOutOfBoundsException &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const jau::RuntimeException &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const std::runtime_error &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const std::invalid_argument &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const std::exception &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const std::string &msg) { + jau::print_native_caught_exception_fwd2java(msg, file, line); + env->ThrowNew(env->FindClass("java/lang/Error"), msg.c_str()); + } catch (const char *msg) { + jau::print_native_caught_exception_fwd2java(msg, file, line); + env->ThrowNew(env->FindClass("java/lang/Error"), msg); + } catch (...) { + jau::print_native_caught_exception_fwd2java(_unknown_exception_type_msg, file, line); + env->ThrowNew(env->FindClass("java/lang/Error"), _unknown_exception_type_msg.c_str()); + } +} + +// +// Basic +// + +jfieldID jau::getField(JNIEnv *env, jobject obj, const char* field_name, const char* field_signature) { + jclass clazz = env->GetObjectClass(obj); + java_exception_check_and_throw(env, E_FILE_LINE); + // J == long + jfieldID res = env->GetFieldID(clazz, field_name, field_signature); + java_exception_check_and_throw(env, E_FILE_LINE); + return res; +} + +jclass jau::search_class(JNIEnv *env, const char *clazz_name) +{ + jclass clazz = env->FindClass(clazz_name); + java_exception_check_and_throw(env, E_FILE_LINE); + if (!clazz) + { + throw jau::InternalError(std::string("no class found: ")+clazz_name, E_FILE_LINE); + } + return clazz; +} + +jclass jau::search_class(JNIEnv *env, jobject obj) +{ + jclass clazz = env->GetObjectClass(obj); + java_exception_check_and_throw(env, E_FILE_LINE); + if (!clazz) + { + throw jau::InternalError("no class found", E_FILE_LINE); + } + return clazz; +} + +jclass jau::search_class(JNIEnv *env, JavaUplink &object) +{ + return search_class(env, object.get_java_class().c_str()); +} + +jmethodID jau::search_method(JNIEnv *env, jclass clazz, const char *method_name, + const char *prototype, bool is_static) +{ + jmethodID method; + if (is_static) + { + method = env->GetStaticMethodID(clazz, method_name, prototype); + } + else + { + method = env->GetMethodID(clazz, method_name, prototype); + } + java_exception_check_and_throw(env, E_FILE_LINE); + + if (!method) + { + throw jau::InternalError(std::string("no method found: ")+method_name, E_FILE_LINE); + } + + return method; +} + +jfieldID jau::search_field(JNIEnv *env, jclass clazz, const char *field_name, + const char *type, bool is_static) +{ + jfieldID field; + if (is_static) + { + field = env->GetStaticFieldID(clazz, field_name, type); + } + else + { + field = env->GetFieldID(clazz, field_name, type); + } + java_exception_check_and_throw(env, E_FILE_LINE); + + if (!field) + { + jau::InternalError(std::string("no field found: ")+field_name, E_FILE_LINE); + } + + return field; +} + +bool jau::from_jboolean_to_bool(jboolean val) +{ + bool result; + + if (val == JNI_TRUE) + { + result = true; + } + else + { + if (val == JNI_FALSE) + { + result = false; + } + else + { + throw jau::InternalError("the jboolean value is not true/false", E_FILE_LINE); + } + } + + return result; +} + +std::string jau::from_jstring_to_string(JNIEnv *env, jstring str) +{ + jboolean is_copy = JNI_TRUE; + if (!str) { + throw std::invalid_argument("String should not be null"); + } + const char *str_chars = (char *)env->GetStringUTFChars(str, &is_copy); + if (!str_chars) { + throw std::bad_alloc(); + } + const std::string string_to_write = std::string(str_chars); + + env->ReleaseStringUTFChars(str, str_chars); + + return string_to_write; +} + +jstring jau::from_string_to_jstring(JNIEnv *env, const std::string & str) +{ + return env->NewStringUTF(str.c_str()); +} + +jobject jau::get_new_arraylist(JNIEnv *env, jsize size, jmethodID *add) +{ + jclass arraylist_class = search_class(env, "java/util/ArrayList"); + jmethodID arraylist_ctor = search_method(env, arraylist_class, "<init>", "(I)V", false); + + jobject result = env->NewObject(arraylist_class, arraylist_ctor, size); + if (!result) + { + throw jau::InternalError("Cannot create instance of class ArrayList", E_FILE_LINE); + } + + *add = search_method(env, arraylist_class, "add", "(Ljava/lang/Object;)Z", false); + + env->DeleteLocalRef(arraylist_class); + return result; +} + + +// +// C++ java_anon implementation +// + +JavaGlobalObj::~JavaGlobalObj() noexcept { + jobject obj = javaObjectRef.getObject(); + if( nullptr == obj || nullptr == mNotifyDeleted ) { + return; + } + JNIEnv *env = *jni_env; + env->CallVoidMethod(obj, mNotifyDeleted); + java_exception_check_and_throw(env, E_FILE_LINE); // would abort() if thrown +} + +// +// C++ java_anon <-> java access, assuming field "long nativeInstance" and native method 'void checkValid()' +// + +// +// C++ java_anon <-> java access, all generic +// + diff --git a/java_jni/jni/jau/Clock.cxx b/java_jni/jni/jau/Clock.cxx new file mode 100644 index 0000000..06afa03 --- /dev/null +++ b/java_jni/jni/jau/Clock.cxx @@ -0,0 +1,65 @@ +/* + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "org_jau_sys_Clock.h" + +#include <cstdint> +#include <cinttypes> + +#include <time.h> + +#include <jau/environment.hpp> + +#include "jau/jni/helper_jni.hpp" + + +static const int64_t NanoPerMilli = 1000000L; +static const int64_t MilliPerOne = 1000L; + +/** + * See <http://man7.org/linux/man-pages/man2/clock_gettime.2.html> + * <p> + * Regarding avoiding kernel via VDSO, + * see <http://man7.org/linux/man-pages/man7/vdso.7.html>, + * clock_gettime seems to be well supported at least on kernel >= 4.4. + * Only bfin and sh are missing, while ia64 seems to be complicated. + */ +jlong Java_org_jau_sys_Clock_currentTimeMillis(JNIEnv *env, jclass clazz) { + (void)env; + (void)clazz; + + struct timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + int64_t res = t.tv_sec * MilliPerOne + t.tv_nsec / NanoPerMilli; + return (jlong)res; +} + +jlong Java_org_jau_sys_Clock_startupTimeMillisImpl(JNIEnv *env, jclass clazz) { + (void)env; + (void)clazz; + + return jau::environment::startupTimeMilliseconds; +} + diff --git a/java_jni/jni/jau/JVM_JNI8.cxx b/java_jni/jni/jau/JVM_JNI8.cxx new file mode 100644 index 0000000..f6487e8 --- /dev/null +++ b/java_jni/jni/jau/JVM_JNI8.cxx @@ -0,0 +1,46 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#include <stdio.h> //required by android to identify NULL +#include <jni.h> + +#if defined (JNI_VERSION_1_8) + +JNIEXPORT jint JNICALL JNI_OnLoad_jaulib_jni_jni(JavaVM *vm, void *reserved) { + (void)vm; + (void)reserved; + return JNI_VERSION_1_8; +} + +JNIEXPORT void JNICALL JNI_OnUnload_jaulib_jni_jni(JavaVM *vm, void *reserved) { + (void)vm; + (void)reserved; +} + +#endif /* defined (JNI_VERSION_1_8) */ + diff --git a/java_jni/jni/jau/MachineDataInfoRuntime.cxx b/java_jni/jni/jau/MachineDataInfoRuntime.cxx new file mode 100644 index 0000000..98ee97a --- /dev/null +++ b/java_jni/jni/jau/MachineDataInfoRuntime.cxx @@ -0,0 +1,211 @@ + +#include <jni.h> + +#include <assert.h> + +#include "jau_sys_MachineDataInfoRuntime.h" + +#include "jau/jni/helper_jni.hpp" + +#if defined(_WIN32) + #include <windows.h> +#else /* assume POSIX sysconf() availability */ + #include <unistd.h> +#endif + +JNIEXPORT jint JNICALL +Java_jau_sys_MachineDataInfoRuntime_getPointerSizeInBytesImpl(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + + return sizeof(void *); +} + +JNIEXPORT jlong JNICALL +Java_jau_sys_MachineDataInfoRuntime_getPageSizeInBytesImpl(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + +#if defined(_WIN32) + SYSTEM_INFO si; + GetSystemInfo(&si); + return (jlong) si.dwPageSize; +#else + return (jlong) sysconf(_SC_PAGESIZE); +#endif +} + +typedef struct { + int8_t c1; + int8_t v; +} struct_alignment_int8; + +typedef struct { + int8_t c1; + int16_t v; +} struct_alignment_int16; + +typedef struct { + int8_t c1; + int32_t v; +} struct_alignment_int32; + +typedef struct { + int8_t c1; + int64_t v; +} struct_alignment_int64; + +typedef struct { + int8_t c1; + int v; +} struct_alignment_int; + +typedef struct { + int8_t c1; + long v; +} struct_alignment_long; + +typedef struct { + int8_t c1; + void * v; +} struct_alignment_pointer; + +typedef struct { + int8_t c1; + float v; +} struct_alignment_float; + +typedef struct { + int8_t c1; + double v; +} struct_alignment_double; + +typedef struct { + int8_t c1; + long double v; +} struct_alignment_ldouble; + +// size_t padding(size_t totalsize, size_t typesize) { return totalsize - typesize - sizeof(char); } +// static size_t alignment(size_t totalsize, size_t typesize) { return totalsize - typesize; } +#define ALIGNMENT(a, b) ( (a) - (b) ) + +JNIEXPORT jint JNICALL +Java_jau_sys_MachineDataInfoRuntime_getAlignmentInt8Impl(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + + return ALIGNMENT(sizeof( struct_alignment_int8 ), sizeof(int8_t)); +} + +JNIEXPORT jint JNICALL +Java_jau_sys_MachineDataInfoRuntime_getAlignmentInt16Impl(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + + return ALIGNMENT(sizeof( struct_alignment_int16 ), sizeof(int16_t)); +} + +JNIEXPORT jint JNICALL +Java_jau_sys_MachineDataInfoRuntime_getAlignmentInt32Impl(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + + return ALIGNMENT(sizeof( struct_alignment_int32 ), sizeof(int32_t)); +} + +JNIEXPORT jint JNICALL +Java_jau_sys_MachineDataInfoRuntime_getAlignmentInt64Impl(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + + return ALIGNMENT(sizeof( struct_alignment_int64 ), sizeof(int64_t)); +} + +JNIEXPORT jint JNICALL +Java_jau_sys_MachineDataInfoRuntime_getAlignmentIntImpl(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + + return ALIGNMENT(sizeof( struct_alignment_int ), sizeof(int)); +} + +JNIEXPORT jint JNICALL +Java_jau_sys_MachineDataInfoRuntime_getAlignmentLongImpl(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + + return ALIGNMENT(sizeof( struct_alignment_long ), sizeof(long)); +} + +JNIEXPORT jint JNICALL +Java_jau_sys_MachineDataInfoRuntime_getAlignmentPointerImpl(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + + return ALIGNMENT(sizeof( struct_alignment_pointer ), sizeof(void *)); +} + +JNIEXPORT jint JNICALL +Java_jau_sys_MachineDataInfoRuntime_getAlignmentFloatImpl(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + + return ALIGNMENT(sizeof( struct_alignment_float ), sizeof(float)); +} + +JNIEXPORT jint JNICALL +Java_jau_sys_MachineDataInfoRuntime_getAlignmentDoubleImpl(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + + return ALIGNMENT(sizeof( struct_alignment_double ), sizeof(double)); +} + +JNIEXPORT jint JNICALL +Java_jau_sys_MachineDataInfoRuntime_getAlignmentLongDoubleImpl(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + + return ALIGNMENT(sizeof( struct_alignment_ldouble ), sizeof(long double)); +} + +JNIEXPORT jint JNICALL +Java_jau_sys_MachineDataInfoRuntime_getSizeOfIntImpl(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + + return sizeof(int); +} + +JNIEXPORT jint JNICALL +Java_jau_sys_MachineDataInfoRuntime_getSizeOfLongImpl(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + + return sizeof(long); +} + +JNIEXPORT jint JNICALL +Java_jau_sys_MachineDataInfoRuntime_getSizeOfFloatImpl(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + + return sizeof(float); +} + +JNIEXPORT jint JNICALL +Java_jau_sys_MachineDataInfoRuntime_getSizeOfDoubleImpl(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + + return sizeof(double); +} + +JNIEXPORT jint JNICALL +Java_jau_sys_MachineDataInfoRuntime_getSizeOfLongDoubleImpl(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + + return sizeof(long double); +} + diff --git a/java_jni/jni/jau/UnixDynamicLinkerImpl_JNI.cxx b/java_jni/jni/jau/UnixDynamicLinkerImpl_JNI.cxx new file mode 100644 index 0000000..9a7a57c --- /dev/null +++ b/java_jni/jni/jau/UnixDynamicLinkerImpl_JNI.cxx @@ -0,0 +1,138 @@ +/* !---- DO NOT EDIT: This file autogenerated by com\sun\gluegen\JavaEmitter.java on Mon Jul 31 16:26:59 PDT 2006 ----! */ + +#include <jni.h> + +#include <assert.h> + +#include "jau_sys_dl_UnixDynamicLinkerImpl.h" + + #include <dlfcn.h> + #include <inttypes.h> + +#ifndef RTLD_DEFAULT + #define RTLD_DEFAULT ((void *) 0) +#endif + +// #define DEBUG_DLOPEN 1 + +#ifdef DEBUG_DLOPEN + typedef void *(*DLOPEN_FPTR_TYPE)(const char *filename, int flag); + #define VERBOSE_ON 1 +#endif + +// #define VERBOSE_ON 1 + +#ifdef VERBOSE_ON + #ifdef ANDROID + #include <android/log.h> + #define DBG_PRINT(...) __android_log_print(ANDROID_LOG_DEBUG, "JogAmp", __VA_ARGS__) + #else + #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) + #endif +#else + #define DBG_PRINT(...) +#endif + +/* + * Class: jau_sys_dl_UnixDynamicLinkerImpl + * Method: dlclose + * Signature: (J)I + */ +JNIEXPORT jint JNICALL +Java_jau_sys_dl_UnixDynamicLinkerImpl_dlclose(JNIEnv *env, jclass _unused, jlong arg0) { + (void)env; + (void)_unused; + + int _res; + _res = dlclose((void *) (intptr_t) arg0); + return _res; +} + + +/* + * Class: jau_sys_dl_UnixDynamicLinkerImpl + * Method: dlerror + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL +Java_jau_sys_dl_UnixDynamicLinkerImpl_dlerror(JNIEnv *env, jclass _unused) { + (void)_unused; + + char * _res; + _res = dlerror(); + if (_res == NULL) return NULL; return env->NewStringUTF(_res); +} + +/* + * Class: jau_sys_dl_UnixDynamicLinkerImpl + * Method: dlopen + * Signature: (Ljava/lang/String;I)J + */ +JNIEXPORT jlong JNICALL +Java_jau_sys_dl_UnixDynamicLinkerImpl_dlopen(JNIEnv *env, jclass _unused, jstring arg0, jint arg1) { + (void)_unused; + + const char* _UTF8arg0 = NULL; + void * _res; +#ifdef DEBUG_DLOPEN + DLOPEN_FPTR_TYPE dlopenFunc = NULL; + DBG_PRINT("XXX dlopen.0\n"); +#endif + + if (arg0 != NULL) { + if (arg0 != NULL) { + _UTF8arg0 = env->GetStringUTFChars(arg0, (jboolean*)NULL); + if (_UTF8arg0 == NULL) { + env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), + "Failed to get UTF-8 chars for argument \"arg0\" in native dispatcher for \"dlopen\""); + return 0; + } + } + } +#ifdef DEBUG_DLOPEN + dlopenFunc = (DLOPEN_FPTR_TYPE) dlsym(RTLD_DEFAULT, "dlopen"); + DBG_PRINT("XXX dlopen.1: lib %s, dlopen-fptr %p %p (%d)\n", _UTF8arg0, dlopen, dlopenFunc, dlopen==dlopenFunc); + _res = dlopen((char *) _UTF8arg0, (int) arg1); + DBG_PRINT("XXX dlopen.2: %p\n", _res); +#else + _res = dlopen((char *) _UTF8arg0, (int) arg1); +#endif + if (arg0 != NULL) { + env->ReleaseStringUTFChars(arg0, _UTF8arg0); + } +#ifdef DEBUG_DLOPEN + DBG_PRINT("XXX dlopen.X\n"); +#endif + return (jlong) (intptr_t) _res; +} + +/* + * Class: jau_sys_dl_UnixDynamicLinkerImpl + * Method: dlsym + * Signature: (JLjava/lang/String;)J + */ +JNIEXPORT jlong JNICALL +Java_jau_sys_dl_UnixDynamicLinkerImpl_dlsym(JNIEnv *env, jclass _unused, jlong arg0, jstring arg1) { + (void)_unused; + + const char* _UTF8arg1 = NULL; + void * _res; + if (arg1 != NULL) { + if (arg1 != NULL) { + _UTF8arg1 = env->GetStringUTFChars(arg1, (jboolean*)NULL); + if (_UTF8arg1 == NULL) { + env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), + "Failed to get UTF-8 chars for argument \"arg1\" in native dispatcher for \"dlsym\""); + return 0; + } + } + } + _res = dlsym((void *) (intptr_t) arg0, (char *) _UTF8arg1); + DBG_PRINT("XXX dlsym: handle %p, symbol %s -> %p\n", (void *) (intptr_t) arg0, _UTF8arg1, _res); + + if (arg1 != NULL) { + env->ReleaseStringUTFChars(arg1, _UTF8arg1); + } + return (jlong) (intptr_t) _res; +} + diff --git a/java_jni/jni/jau/WindowsDynamicLinkerImpl_JNI.cxx b/java_jni/jni/jau/WindowsDynamicLinkerImpl_JNI.cxx new file mode 100644 index 0000000..f9ee9a7 --- /dev/null +++ b/java_jni/jni/jau/WindowsDynamicLinkerImpl_JNI.cxx @@ -0,0 +1,107 @@ +/* !---- DO NOT EDIT: This file autogenerated by com\sun\gluegen\JavaEmitter.java on Tue May 27 02:37:55 PDT 2008 ----! */ + +#include <jni.h> +#include <stdlib.h> + +#include <assert.h> + +#include "jau_sys_dl_WindowsDynamicLinkerImpl.h" + + #include <windows.h> + /* This typedef is apparently needed for compilers before VC8, + and for the embedded ARM compilers we're using */ + #if !defined(__MINGW64__) && ( (_MSC_VER < 1400) || defined(UNDER_CE) ) + typedef int intptr_t; + #endif + /* GetProcAddress doesn't exist in A/W variants under desktop Windows */ + #ifndef UNDER_CE + #define GetProcAddressA GetProcAddress + #endif + +/* Java->C glue code: + * Java package: jogamp.common.os.WindowsDynamicLinkerImpl + * Java method: int FreeLibrary(long hLibModule) + * C function: BOOL FreeLibrary(HANDLE hLibModule); + */ +JNIEXPORT jint JNICALL +Java_jau_sys_dl_WindowsDynamicLinkerImpl_FreeLibrary(JNIEnv *env, jclass _unused, jlong hLibModule) { + (void)env; + (void)_unused; + + BOOL _res; + _res = FreeLibrary((HANDLE) (intptr_t) hLibModule); + return _res; +} + + +/* Java->C glue code: + * Java package: jogamp.common.os.WindowsDynamicLinkerImpl + * Java method: int GetLastError() + * C function: DWORD GetLastError(void); + */ +JNIEXPORT jint JNICALL +Java_jau_sys_dl_WindowsDynamicLinkerImpl_GetLastError(JNIEnv *env, jclass _unused) { + (void)env; + (void)_unused; + + DWORD _res; + _res = GetLastError(); + return _res; +} + + +/* Java->C glue code: + * Java package: jogamp.common.os.WindowsDynamicLinkerImpl + * Java method: long GetProcAddressA(long hModule, java.lang.String lpProcName) + * C function: PROC GetProcAddressA(HANDLE hModule, LPCSTR lpProcName); + */ +JNIEXPORT jlong JNICALL +Java_jau_sys_dl_WindowsDynamicLinkerImpl_GetProcAddressA(JNIEnv *env, jclass _unused, jlong hModule, jstring lpProcName) { + (void)_unused; + + const char* _strchars_lpProcName = NULL; + PROC _res; + if (lpProcName != NULL) { + _strchars_lpProcName = env->GetStringUTFChars(lpProcName, (jboolean*)NULL); + if (_strchars_lpProcName == NULL) { + env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), + "Failed to get UTF-8 chars for argument \"lpProcName\" in native dispatcher for \"GetProcAddressA\""); + return 0; + } + } + _res = GetProcAddressA((HANDLE) (intptr_t) hModule, (LPCSTR) _strchars_lpProcName); + if (lpProcName != NULL) { + env->ReleaseStringUTFChars(lpProcName, _strchars_lpProcName); + } + return (jlong) (intptr_t) _res; +} + + +/* Java->C glue code: + * Java package: jogamp.common.os.WindowsDynamicLinkerImpl + * Java method: long LoadLibraryW(java.lang.String lpLibFileName) + * C function: HANDLE LoadLibraryW(LPCWSTR lpLibFileName); + */ +JNIEXPORT jlong JNICALL +Java_jau_sys_dl_WindowsDynamicLinkerImpl_LoadLibraryW(JNIEnv *env, jclass _unused, jstring lpLibFileName) { + (void)_unused; + + jchar* _strchars_lpLibFileName = NULL; + HANDLE _res; + if (lpLibFileName != NULL) { + _strchars_lpLibFileName = (jchar *) calloc(env->GetStringLength(lpLibFileName) + 1, sizeof(jchar)); + if (_strchars_lpLibFileName == NULL) { + env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), + "Could not allocate temporary buffer for copying string argument \"lpLibFileName\" in native dispatcher for \"LoadLibraryW\""); + return 0; + } + env->GetStringRegion(lpLibFileName, 0, env->GetStringLength(lpLibFileName), _strchars_lpLibFileName); + } + _res = LoadLibraryW((LPCWSTR) _strchars_lpLibFileName); + if (lpLibFileName != NULL) { + free((void*) _strchars_lpLibFileName); + } + return (jlong) (intptr_t) _res; +} + + diff --git a/java_jni/jni/jni_mem.cxx b/java_jni/jni/jni_mem.cxx new file mode 100644 index 0000000..981c6e5 --- /dev/null +++ b/java_jni/jni/jni_mem.cxx @@ -0,0 +1,169 @@ +/* + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Author: Petre Eftime <[email protected]> + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <cstdio> + +#include <jau/debug.hpp> +#include <jau/jni/jni_mem.hpp> + +JavaVM* vm; +thread_local JNIEnvContainer jni_env; + +jint JNI_OnLoad(JavaVM *initVM, void *reserved) { + (void)reserved; // warning + vm = initVM; + return JNI_VERSION_1_8; +} + +JNIEnv *JNIEnvContainer::operator*() { + attach(); + return env; +} + +JNIEnv *JNIEnvContainer::operator->() { + attach(); + return env; +} + +JNIEnvContainer::JNIEnvContainer() {} + +JNIEnvContainer::~JNIEnvContainer() { + detach(); +} + +void JNIEnvContainer::attach() { + if (env != nullptr) { + return; + } + JNIEnv *newEnv = nullptr; + int envRes; + + envRes = vm->GetEnv((void **) &env, JNI_VERSION_1_8) ; + if( JNI_EDETACHED == envRes ) { + envRes = vm->AttachCurrentThreadAsDaemon((void**) &newEnv, NULL); + if( JNI_OK != envRes ) { + throw jau::RuntimeException("Attach to VM failed", E_FILE_LINE); + } + env = newEnv; + } else if( JNI_OK != envRes ) { + throw jau::RuntimeException("GetEnv of VM failed", E_FILE_LINE); + } + if (env==NULL) { + throw jau::RuntimeException("GetEnv of VM is NULL", E_FILE_LINE); + } + needsDetach = NULL != newEnv; +} + +void JNIEnvContainer::detach() { + if (env == nullptr) { + return; + } + if( needsDetach ) { + vm->DetachCurrentThread(); + } + env = nullptr; + needsDetach = false; +} + +JNIGlobalRef::JNIGlobalRef() noexcept { + this->object = nullptr; + DBG_JNI_PRINT("JNIGlobalRef::def_ctor nullptr"); +} + +JNIGlobalRef::JNIGlobalRef(jobject _object) { + if( nullptr == _object ) { + throw jau::RuntimeException("JNIGlobalRef ctor null jobject", E_FILE_LINE); + } + this->object = jni_env->NewGlobalRef(_object); + DBG_JNI_PRINT("JNIGlobalRef::def_ctor %p -> %p", _object, this->object); +} + +JNIGlobalRef::JNIGlobalRef(const JNIGlobalRef &o) { + if( nullptr == o.object ) { + throw jau::RuntimeException("Other JNIGlobalRef jobject is null", E_FILE_LINE); + } + object = jni_env->NewGlobalRef(o.object); + DBG_JNI_PRINT("JNIGlobalRef::copy_ctor %p -> %p", o.object, object); +} +JNIGlobalRef::JNIGlobalRef(JNIGlobalRef &&o) noexcept +: object(o.object) { + DBG_JNI_PRINT("JNIGlobalRef::move_ctor %p (nulled) -> %p", o.object, object); + o.object = nullptr; +} +JNIGlobalRef& JNIGlobalRef::operator=(const JNIGlobalRef &o) { + if( &o == this ) { + return *this; + } + JNIEnv * env = *jni_env; + if( nullptr != object ) { // always + env->DeleteGlobalRef(object); + } + if( nullptr == o.object ) { + throw jau::RuntimeException("Other JNIGlobalRef jobject is null", E_FILE_LINE); + } + object = jni_env->NewGlobalRef(o.object); + DBG_JNI_PRINT("JNIGlobalRef::copy_assign %p -> %p", o.object, object); + return *this; +} +JNIGlobalRef& JNIGlobalRef::operator=(JNIGlobalRef &&o) noexcept { + object = o.object; + DBG_JNI_PRINT("JNIGlobalRef::move_assign %p (nulled) -> %p", o.object, object); + o.object = nullptr; + return *this; +} + +JNIGlobalRef::~JNIGlobalRef() noexcept { + try { + JNIEnv * env = *jni_env; + if( nullptr == env ) { + ABORT("JNIGlobalRef dtor null JNIEnv"); + } + DBG_JNI_PRINT("JNIGlobalRef::dtor %p", object); + if( nullptr != object ) { + // due to move ctor and assignment, we accept nullptr object + env->DeleteGlobalRef(object); + } + } catch (std::exception &e) { + fprintf(stderr, "JNIGlobalRef dtor: Caught %s\n", e.what()); + } +} + +void JNIGlobalRef::clear() noexcept { + DBG_JNI_PRINT("JNIGlobalRef::clear %p (nulled) -> null", object); + object = nullptr; +} + +bool JNIGlobalRef::operator==(const JNIGlobalRef& rhs) const noexcept { + if( &rhs == this ) { + DBG_JNI_PRINT("JNIGlobalRef::== true: %p == %p (ptr)", object, rhs.object); + return true; + } + bool res = JNI_TRUE == jni_env->IsSameObject(object, rhs.object); + DBG_JNI_PRINT("JNIGlobalRef::== %d: %p == %p (IsSameObject)", res, object, rhs.object); + return res; +} diff --git a/java_jni/manifest.txt.in b/java_jni/manifest.txt.in new file mode 100644 index 0000000..7f70c4c --- /dev/null +++ b/java_jni/manifest.txt.in @@ -0,0 +1,30 @@ +Manifest-Version: 1.0 +Bundle-Date: @BUILD_TSTAMP@ +Bundle-ManifestVersion: 2 +Bundle-Name: org.jau.sys.dl +Bundle-SymbolicName: org.jau.sys.dl +Bundle-Version: @VERSION_SHORT@ +Export-Package: org.jau.sys.dl +Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.9))" +Package-Title: org.jau.sys.dl +Package-Vendor: Gothel Software +Package-Version: @VERSION_SHORT@ +Specification-Title: Jaulib JNI +Specification-Vendor: Gothel Software +Specification-Version: @VERSION_API@ +Implementation-Title: Jaulib JNI +Implementation-Vendor: Gothel Software +Implementation-Version: @VERSION@ +Implementation-Commit: @VERSION_SHA1@ +Implementation-URL: http://www.jausoft.com/ +Extension-Name: org.jau.sys.dl +Trusted-Library: true +Permissions: all-permissions +Application-Library-Allowable-Codebase: * + +Name: org/jau/sys/dl +Sealed: false + +Name: jau/sys/dl +Sealed: false + diff --git a/java_jni/org/jau/sys/Clock.java b/java_jni/org/jau/sys/Clock.java new file mode 100644 index 0000000..43beb63 --- /dev/null +++ b/java_jni/org/jau/sys/Clock.java @@ -0,0 +1,53 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package org.jau.sys; + +public class Clock { + private static long t0; + static { + t0 = startupTimeMillisImpl(); + } + private static native long startupTimeMillisImpl(); + + /** + * Returns current monotonic time in milliseconds. + */ + public static native long currentTimeMillis(); + + /** + * Returns the startup time in monotonic time in milliseconds of the native module. + */ + public static long startupTimeMillis() { return t0; } + + /** + * Returns current elapsed monotonic time in milliseconds since module startup, see {@link #startupTimeMillis()}. + */ + public static long elapsedTimeMillis() { return currentTimeMillis() - t0; } + + /** + * Returns elapsed monotonic time in milliseconds since module startup comparing against the given timestamp, see {@link #startupTimeMillis()}. + */ + public static long elapsedTimeMillis(final long current_ts) { return current_ts - t0; } + +} diff --git a/java_jni/org/jau/sys/dl/DynamicLibraryBundle.java b/java_jni/org/jau/sys/dl/DynamicLibraryBundle.java new file mode 100644 index 0000000..6a5eb0b --- /dev/null +++ b/java_jni/org/jau/sys/dl/DynamicLibraryBundle.java @@ -0,0 +1,422 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2010 Gothel Software e.K. + * Copyright (c) 2010 JogAmp Community. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package org.jau.sys.dl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +import org.jau.sys.JNILibrary; +import org.jau.util.parallel.RunnableExecutor; + +/** + * Provides bundling of:<br> + * <ul> + * <li>The to-be-glued native library, eg OpenGL32.dll. From here on this is referred as the Tool.</li> + * <li>The JNI glue-code native library, eg jogl_desktop.dll. From here on this is referred as the Glue</li> + * </ul> + * <p> + * An {@link DynamicLibraryBundleInfo} instance is being passed in the constructor, + * providing the required information about the tool and glue libraries. + * The ClassLoader of it's implementation is also being used to help locating the native libraries. + * </p> + * An instance provides a complete {@link com.jogamp.common.os.DynamicLookupHelper} + * to {@link com.jogamp.gluegen.runtime.ProcAddressTable#reset(com.jogamp.common.os.DynamicLookupHelper) reset} + * the {@link com.jogamp.gluegen.runtime.ProcAddressTable}.<br> + * At construction, it: + * <ul> + * <li> loads the Tool native library via + * {@link com.jogamp.common.os.NativeLibrary#open(java.lang.String, java.lang.ClassLoader, boolean) NativeLibrary's open method}</li> + * <li> loads the {@link org.jau.sys.JNIJarLibrary.common.jvm.JNILibLoaderBase#loadLibrary(java.lang.String, java.lang.String[], boolean, ClassLoader) Glue native library}</li> + * <li> resolves the Tool's {@link com.jogamp.common.os.DynamicLibraryBundleInfo#getToolGetProcAddressFuncNameList() GetProcAddress}. (optional)</li> + * </ul> + */ +public class DynamicLibraryBundle implements DynamicLookupHelper { + private final DynamicLibraryBundleInfo info; + + protected final List<NativeLibrary> nativeLibraries; + private final DynamicLinker dynLinkGlobal; + private final List<List<String>> toolLibNames; + private final List<String> glueLibNames; + private final boolean[] toolLibLoaded; + + private int toolLibLoadedNumber; + + private final boolean[] glueLibLoaded; + private int glueLibLoadedNumber; + + private long toolGetProcAddressHandle; + private boolean toolGetProcAddressComplete; + private HashSet<String> toolGetProcAddressFuncNameSet; + private final List<String> toolGetProcAddressFuncNameList; + + /** Returns the default {@link RunnableExecutor#currentThreadExecutor}. */ + public static RunnableExecutor getDefaultRunnableExecutor() { + return RunnableExecutor.currentThreadExecutor; + } + + /** + * Instantiates and loads all {@link NativeLibrary}s incl. JNI libraries. + * <p> + * The ClassLoader of the {@link DynamicLibraryBundleInfo} implementation class + * is being used to help locating the native libraries. + * </p> + */ + public DynamicLibraryBundle(final DynamicLibraryBundleInfo info) { + if(null==info) { + throw new RuntimeException("Null DynamicLibraryBundleInfo"); + } + this.info = info; + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - DynamicLibraryBundle.init start with: "+info.getClass().getName()); + } + nativeLibraries = new ArrayList<NativeLibrary>(); + toolLibNames = info.getToolLibNames(); + glueLibNames = info.getGlueLibNames(); + toolLibLoaded = new boolean[toolLibNames.size()]; + if(DEBUG) { + if( toolLibNames.size() == 0 ) { + System.err.println("No Tool native library names given"); + } + + if( glueLibNames.size() == 0 ) { + System.err.println("No Glue native library names given"); + } + } + + for(int i=toolLibNames.size()-1; i>=0; i--) { + toolLibLoaded[i] = false; + } + glueLibLoaded = new boolean[glueLibNames.size()]; + for(int i=glueLibNames.size()-1; i>=0; i--) { + glueLibLoaded[i] = false; + } + + { + final DynamicLinker[] _dynLinkGlobal = { null }; + info.getLibLoaderExecutor().invoke(true, new Runnable() { + @Override + public void run() { + _dynLinkGlobal[0] = loadLibraries(); + } } ) ; + dynLinkGlobal = _dynLinkGlobal[0]; + } + + toolGetProcAddressFuncNameList = info.getToolGetProcAddressFuncNameList(); + if( null != toolGetProcAddressFuncNameList ) { + toolGetProcAddressFuncNameSet = new HashSet<String>(toolGetProcAddressFuncNameList); + toolGetProcAddressHandle = getToolGetProcAddressHandle(); + toolGetProcAddressComplete = 0 != toolGetProcAddressHandle; + } else { + toolGetProcAddressFuncNameSet = new HashSet<String>(); + toolGetProcAddressHandle = 0; + toolGetProcAddressComplete = true; + } + if(DEBUG) { + System.err.println("DynamicLibraryBundle.init Summary: "+info.getClass().getName()); + System.err.println(" toolGetProcAddressFuncNameList: "+toolGetProcAddressFuncNameList+", complete: "+toolGetProcAddressComplete+", 0x"+Long.toHexString(toolGetProcAddressHandle)); + System.err.println(" Tool Lib Names : "+toolLibNames); + System.err.println(" Tool Lib Loaded: "+getToolLibLoadedNumber()+"/"+getToolLibNumber()+" "+Arrays.toString(toolLibLoaded)+", complete "+isToolLibComplete()); + System.err.println(" Glue Lib Names : "+glueLibNames); + System.err.println(" Glue Lib Loaded: "+getGlueLibLoadedNumber()+"/"+getGlueLibNumber()+" "+Arrays.toString(glueLibLoaded)+", complete "+isGlueLibComplete()); + System.err.println(" All Complete: "+isLibComplete()); + System.err.println(" LibLoaderExecutor: "+info.getLibLoaderExecutor().getClass().getName()); + } + } + + /** Unload all {@link NativeLibrary}s, and remove all references. */ + public final void destroy() { + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - DynamicLibraryBundle.destroy() START: "+info.getClass().getName()); + } + toolGetProcAddressFuncNameSet = null; + toolGetProcAddressHandle = 0; + toolGetProcAddressComplete = false; + for(int i = 0; i<nativeLibraries.size(); i++) { + nativeLibraries.get(i).close(); + } + nativeLibraries.clear(); + toolLibNames.clear(); + glueLibNames.clear(); + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - DynamicLibraryBundle.destroy() END: "+info.getClass().getName()); + } + } + + public final boolean isLibComplete() { + return isToolLibComplete() && isGlueLibComplete() ; + } + + public final int getToolLibNumber() { + return toolLibNames.size(); + } + + public final int getToolLibLoadedNumber() { + return toolLibLoadedNumber; + } + + /** + * @return true if all tool libraries are loaded, + * otherwise false. + * + * @see DynamicLibraryBundleInfo#getToolLibNames() + */ + public final boolean isToolLibComplete() { + final int toolLibNumber = getToolLibNumber(); + return toolGetProcAddressComplete && + ( 0 == toolLibNumber || null != dynLinkGlobal ) && + toolLibNumber == getToolLibLoadedNumber(); + } + + public final boolean isToolLibLoaded() { + return 0 < toolLibLoadedNumber; + } + + public final boolean isToolLibLoaded(final int i) { + if(0 <= i && i < toolLibLoaded.length) { + return toolLibLoaded[i]; + } + return false; + } + + public final int getGlueLibNumber() { + return glueLibNames.size(); + } + + public final int getGlueLibLoadedNumber() { + return glueLibLoadedNumber; + } + + /** + * @return true if the last entry has been loaded, + * while ignoring the preload dependencies. + * Otherwise false. + * + * @see DynamicLibraryBundleInfo#getGlueLibNames() + */ + public final boolean isGlueLibComplete() { + return 0 == getGlueLibNumber() || isGlueLibLoaded(getGlueLibNumber() - 1); + } + + public final boolean isGlueLibLoaded(final int i) { + if(0 <= i && i < glueLibLoaded.length) { + return glueLibLoaded[i]; + } + return false; + } + + public final DynamicLibraryBundleInfo getBundleInfo() { return info; } + + protected final long getToolGetProcAddressHandle() throws SecurityException { + if(!isToolLibLoaded()) { + return 0; + } + long aptr = 0; + for (int i=0; i < toolGetProcAddressFuncNameList.size(); i++) { + final String name = toolGetProcAddressFuncNameList.get(i); + aptr = dynamicLookupFunctionOnLibs(name); + if(DEBUG) { + System.err.println("getToolGetProcAddressHandle: "+name+" -> 0x"+Long.toHexString(aptr)); + } + } + return aptr; + } + + protected static final NativeLibrary loadFirstAvailable(final List<String> libNames, + final boolean searchSystemPath, + final boolean searchSystemPathFirst, + final ClassLoader loader, final boolean global) throws SecurityException { + for (int i=0; i < libNames.size(); i++) { + final NativeLibrary lib = NativeLibrary.open(libNames.get(i), searchSystemPath, searchSystemPathFirst, loader, global); + if (lib != null) { + return lib; + } + } + return null; + } + + final DynamicLinker loadLibraries() throws SecurityException { + int i; + toolLibLoadedNumber = 0; + final ClassLoader cl = info.getClass().getClassLoader(); + NativeLibrary lib = null; + DynamicLinker dynLinkGlobal = null; + + for (i=0; i < toolLibNames.size(); i++) { + final List<String> libNames = toolLibNames.get(i); + if( null != libNames && libNames.size() > 0 ) { + lib = loadFirstAvailable(libNames, + info.searchToolLibInSystemPath(), + info.searchToolLibSystemPathFirst(), + cl, info.shallLinkGlobal()); + if ( null == lib ) { + if(DEBUG) { + System.err.println("Unable to load any Tool library of: "+libNames); + } + } else { + if( null == dynLinkGlobal ) { + dynLinkGlobal = lib.dynamicLinker(); + } + nativeLibraries.add(lib); + toolLibLoaded[i]=true; + toolLibLoadedNumber++; + if(DEBUG) { + System.err.println("Loaded Tool library: "+lib); + } + } + } + } + if( toolLibNames.size() > 0 && !isToolLibLoaded() ) { + if(DEBUG) { + System.err.println("No Tool libraries loaded"); + } + return dynLinkGlobal; + } + + glueLibLoadedNumber = 0; + for (i=0; i < glueLibNames.size(); i++) { + final String libName = glueLibNames.get(i); + final boolean ignoreError = true; + boolean res; + try { + res = JNILibrary.loadLibrary(libName, ignoreError, cl); + if(DEBUG && !res) { + System.err.println("Info: Could not load JNI/Glue library: "+libName); + } + } catch (final UnsatisfiedLinkError e) { + res = false; + if(DEBUG) { + System.err.println("Unable to load JNI/Glue library: "+libName); + e.printStackTrace(); + } + } + glueLibLoaded[i] = res; + if(res) { + glueLibLoadedNumber++; + } + } + + return dynLinkGlobal; + } + + /** + * @param funcName + * @return + * @throws SecurityException if user is not granted access for the library set. + */ + private final long dynamicLookupFunctionOnLibs(final String funcName) throws SecurityException { + if(!isToolLibLoaded() || null==funcName) { + if(DEBUG_LOOKUP && !isToolLibLoaded()) { + System.err.println("Lookup-Native: <" + funcName + "> ** FAILED ** Tool native library not loaded"); + } + return 0; + } + long addr = 0; + NativeLibrary lib = null; + + if( info.shallLookupGlobal() ) { + // Try a global symbol lookup first .. + // addr = NativeLibrary.dynamicLookupFunctionGlobal(funcName); + addr = dynLinkGlobal.lookupSymbolGlobal(funcName); + } + // Look up this function name in all known libraries + for (int i=0; 0==addr && i < nativeLibraries.size(); i++) { + lib = nativeLibraries.get(i); + addr = lib.dynamicLookupFunction(funcName); + } + if(DEBUG_LOOKUP) { + final String libName = ( null == lib ) ? "GLOBAL" : lib.toString(); + if(0!=addr) { + System.err.println("Lookup-Native: <" + funcName + "> 0x" + Long.toHexString(addr) + " in lib " + libName ); + } else { + System.err.println("Lookup-Native: <" + funcName + "> ** FAILED ** in libs " + nativeLibraries); + } + } + return addr; + } + + private final long toolDynamicLookupFunction(final String funcName) { + if(0 != toolGetProcAddressHandle) { + final long addr = info.toolGetProcAddress(toolGetProcAddressHandle, funcName); + if(DEBUG_LOOKUP) { + if(0!=addr) { + System.err.println("Lookup-Tool: <"+funcName+"> 0x"+Long.toHexString(addr)+", via tool 0x"+Long.toHexString(toolGetProcAddressHandle)); + } + } + return addr; + } + return 0; + } + + @Override + public final void claimAllLinkPermission() throws SecurityException { + for (int i=0; i < nativeLibraries.size(); i++) { + nativeLibraries.get(i).claimAllLinkPermission(); + } + } + @Override + public final void releaseAllLinkPermission() throws SecurityException { + for (int i=0; i < nativeLibraries.size(); i++) { + nativeLibraries.get(i).releaseAllLinkPermission(); + } + } + + @Override + public final long dynamicLookupFunction(final String funcName) throws SecurityException { + if(!isToolLibLoaded() || null==funcName) { + if(DEBUG_LOOKUP && !isToolLibLoaded()) { + System.err.println("Lookup: <" + funcName + "> ** FAILED ** Tool native library not loaded"); + } + return 0; + } + + if(toolGetProcAddressFuncNameSet.contains(funcName)) { + return toolGetProcAddressHandle; + } + + long addr = 0; + final boolean useToolGetProcAdressFirst = info.useToolGetProcAdressFirst(funcName); + + if(useToolGetProcAdressFirst) { + addr = toolDynamicLookupFunction(funcName); + } + if(0==addr) { + addr = dynamicLookupFunctionOnLibs(funcName); + } + if(0==addr && !useToolGetProcAdressFirst) { + addr = toolDynamicLookupFunction(funcName); + } + return addr; + } + + @Override + public final boolean isFunctionAvailable(final String funcName) throws SecurityException { + return 0 != dynamicLookupFunction(funcName); + } +} + diff --git a/java_jni/org/jau/sys/dl/DynamicLibraryBundleInfo.java b/java_jni/org/jau/sys/dl/DynamicLibraryBundleInfo.java new file mode 100644 index 0000000..a66168f --- /dev/null +++ b/java_jni/org/jau/sys/dl/DynamicLibraryBundleInfo.java @@ -0,0 +1,128 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2010 Gothel Software e.K. + * Copyright (c) 2010 JogAmp Community. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package org.jau.sys.dl; + +import java.util.List; + +import org.jau.util.parallel.RunnableExecutor; + +public interface DynamicLibraryBundleInfo { + public static final boolean DEBUG = DynamicLibraryBundle.DEBUG; + + /** + * Returns {@code true} if tool libraries shall be searched in the system path <i>(default)</i>, otherwise {@code false}. + * @since 2.4.0 + */ + public boolean searchToolLibInSystemPath(); + + /** + * Returns {@code true} if system path shall be searched <i>first</i> <i>(default)</i>, rather than searching it last. + * <p> + * If {@link #searchToolLibInSystemPath()} is {@code false} the return value is ignored. + * </p> + * @since 2.4.0 + */ + public boolean searchToolLibSystemPathFirst(); + + /** + * If a {@link SecurityManager} is installed, user needs link permissions + * for the named libraries. + * + * @return a list of Tool library names or alternative library name lists.<br> + * <ul> + * <li>GL/GLU example Unix: [ [ "libGL.so.1", "libGL.so", "GL" ], [ "libGLU.so", "GLU" ] ] </li> + * <li>GL/GLU example Windows: [ "OpenGL32", "GLU32" ] </li> + * <li>Cg/CgGL example: [ [ "libCg.so", "Cg" ], [ "libCgGL.so", "CgGL" ] ] </li> + * </pre> + */ + public List<List<String>> getToolLibNames(); + + /** + * If a {@link SecurityManager} is installed, user needs link permissions + * for the named libraries. + * + * @return a list of Glue library names.<br> + * <ul> + * <li>GL: [ "nativewindow_x11", "jogl_gl2es12", "jogl_desktop" ] </li> + * <li>NEWT: [ "nativewindow_x11", "newt" ] </li> + * <li>Cg: [ "nativewindow_x11", "jogl_cg" ] </li> + * </ul><br> + * Only the last entry is crucial, ie all other are optional preload dependencies and may generate errors, + * which are ignored. + */ + public List<String> getGlueLibNames(); + + /** + * May return the native libraries <pre>GetProcAddressFunc</pre> names, the first found function is being used.<br> + * This could be eg: <pre> glXGetProcAddressARB, glXGetProcAddressARB </pre>.<br> + * If your Tool does not has this facility, just return null. + * @see #toolGetProcAddress(long, String) + */ + public List<String> getToolGetProcAddressFuncNameList() ; + + /** + * May implement the lookup function using the Tools facility.<br> + * The actual function pointer is provided to allow proper bootstrapping of the ProcAddressTable, + * using one of the provided function names by {@link #getToolGetProcAddressFuncNameList()}.<br> + */ + public long toolGetProcAddress(long toolGetProcAddressHandle, String funcName); + + /** + * @param funcName + * @return true if {@link #toolGetProcAddress(long, String)} shall be tried before + * the system loader for the given function lookup. Otherwise false. + * Default is <b>true</b>. + */ + public boolean useToolGetProcAdressFirst(String funcName); + + /** @return true if the native library symbols shall be made available for symbol resolution of subsequently loaded libraries. */ + public boolean shallLinkGlobal(); + + /** + * If method returns <code>true</code> <i>and</i> if a {@link SecurityManager} is installed, user needs link permissions + * for <b>all</b> libraries, i.e. for <code>new RuntimePermission("loadLibrary.*");</code>! + * + * @return true if the dynamic symbol lookup shall happen system wide, over all loaded libraries. + * Otherwise only the loaded native libraries are used for lookup, which shall be the default. + */ + public boolean shallLookupGlobal(); + + /** + * Returns a suitable {@link RunnableExecutor} implementation, which is being used + * to load the <code>tool</code> and <code>glue</code> native libraries. + * <p> + * This allows the generic {@link DynamicLibraryBundle} implementation to + * load the native libraries on a designated thread. + * </p> + * <p> + * An implementation may return {@link DynamicLibraryBundle#getDefaultRunnableExecutor()}. + * </p> + */ + public RunnableExecutor getLibLoaderExecutor(); +} + + diff --git a/java_jni/org/jau/sys/dl/DynamicLinker.java b/java_jni/org/jau/sys/dl/DynamicLinker.java new file mode 100644 index 0000000..2bba77b --- /dev/null +++ b/java_jni/org/jau/sys/dl/DynamicLinker.java @@ -0,0 +1,113 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2013 Gothel Software e.K. + * Copyright (c) 2013 JogAmp Community. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package org.jau.sys.dl; + +/** Low level secure dynamic linker access. */ +public interface DynamicLinker { + public static final boolean DEBUG = NativeLibrary.DEBUG; + public static final boolean DEBUG_LOOKUP = NativeLibrary.DEBUG_LOOKUP; + + /** + * @throws SecurityException if user is not granted global access + */ + public void claimAllLinkPermission() throws SecurityException; + + /** + * @throws SecurityException if user is not granted global access + */ + public void releaseAllLinkPermission() throws SecurityException; + + /** + * If a {@link SecurityManager} is installed, user needs link permissions + * for the named library. + * <p> + * Opens the named library, allowing system wide access for other <i>users</i>. + * </p> + * + * @param pathname the full pathname for the library to open + * @param debug set to true to enable debugging + * @return the library handle, maybe 0 if not found. + * @throws SecurityException if user is not granted access for the named library. + */ + public long openLibraryGlobal(String pathname, boolean debug) throws SecurityException; + + /** + * If a {@link SecurityManager} is installed, user needs link permissions + * for the named library. + * <p> + * Opens the named library, restricting access to this process. + * </p> + * + * @param pathname the full pathname for the library to open + * @param debug set to true to enable debugging + * @return the library handle, maybe 0 if not found. + * @throws SecurityException if user is not granted access for the named library. + */ + public long openLibraryLocal(String pathname, boolean debug) throws SecurityException; + + /** + * If a {@link SecurityManager} is installed, user needs link permissions + * for <b>all</b> libraries, i.e. for <code>new RuntimePermission("loadLibrary.*");</code>! + * + * @param symbolName global symbol name to lookup up system wide. + * @return the library handle, maybe 0 if not found. + * @throws SecurityException if user is not granted access for all libraries. + */ + public long lookupSymbolGlobal(String symbolName) throws SecurityException; + + /** + * Security checks are implicit by previous call of + * {@link #openLibraryLocal(String, boolean)} or {@link #openLibraryGlobal(String, boolean)} + * retrieving the <code>librarHandle</code>. + * + * @param libraryHandle a library handle previously retrieved via {@link #openLibraryLocal(String, boolean)} or {@link #openLibraryGlobal(String, boolean)}. + * @param symbolName global symbol name to lookup up system wide. + * @return the library handle, maybe 0 if not found. + * @throws IllegalArgumentException in case case <code>libraryHandle</code> is unknown. + * @throws SecurityException if user is not granted access for the given library handle + */ + public long lookupSymbol(long libraryHandle, String symbolName) throws SecurityException, IllegalArgumentException; + + /** + * Security checks are implicit by previous call of + * {@link #openLibraryLocal(String, boolean)} or {@link #openLibraryGlobal(String, boolean)} + * retrieving the <code>librarHandle</code>. + * + * @param libraryHandle a library handle previously retrieved via {@link #openLibraryLocal(String, boolean)} or {@link #openLibraryGlobal(String, boolean)}. + * @param debug set to true to enable debugging + * @throws IllegalArgumentException in case case <code>libraryHandle</code> is unknown. + * @throws SecurityException if user is not granted access for the given library handle + */ + public void closeLibrary(long libraryHandle, boolean debug) throws SecurityException, IllegalArgumentException; + + /** + * Returns a string containing the last error. + * Maybe called for debuging purposed if any method fails. + * @return error string, maybe null. A null or non-null value has no semantics. + */ + public String getLastError(); +} diff --git a/java_jni/org/jau/sys/dl/DynamicLookupHelper.java b/java_jni/org/jau/sys/dl/DynamicLookupHelper.java new file mode 100644 index 0000000..4e9a23c --- /dev/null +++ b/java_jni/org/jau/sys/dl/DynamicLookupHelper.java @@ -0,0 +1,57 @@ +/** + * Author: Sven Gothel <[email protected]> + * Author: Kenneth Bradley Russell + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2011 Gothel Software e.K. + * Copyright (c) 2011 JogAmp Community. + * Copyright (c) 2003-2005 Sun Microsystems, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package org.jau.sys.dl; + +import org.jau.sys.Debug; + +public interface DynamicLookupHelper { + public static final boolean DEBUG = Debug.debug("NativeLibrary"); + public static final boolean DEBUG_LOOKUP = Debug.debug("NativeLibrary.Lookup"); + + /** + * @throws SecurityException if user is not granted access for the library set. + */ + public void claimAllLinkPermission() throws SecurityException; + /** + * @throws SecurityException if user is not granted access for the library set. + */ + public void releaseAllLinkPermission() throws SecurityException; + + /** + * Returns the function handle for function 'funcName'. + * @throws SecurityException if user is not granted access for the library set. + */ + public long dynamicLookupFunction(String funcName) throws SecurityException; + + /** + * Queries whether function 'funcName' is available. + * @throws SecurityException if user is not granted access for the library set. + */ + public boolean isFunctionAvailable(String funcName) throws SecurityException; +} diff --git a/java_jni/org/jau/sys/dl/NativeLibrary.java b/java_jni/org/jau/sys/dl/NativeLibrary.java new file mode 100644 index 0000000..d278b42 --- /dev/null +++ b/java_jni/org/jau/sys/dl/NativeLibrary.java @@ -0,0 +1,298 @@ +/** + * Author: Sven Gothel <[email protected]> + * Author: Kenneth Bradley Russell + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2011 Gothel Software e.K. + * Copyright (c) 2011 JogAmp Community. + * Copyright (c) 2006 Sun Microsystems, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package org.jau.sys.dl; + +import java.util.Iterator; +import java.util.List; + +import org.jau.lang.ExceptionUtils; +import org.jau.sys.JNILibrary; +import org.jau.sys.PlatformProps; + +import jau.sys.dl.BionicDynamicLinker32bitImpl; +import jau.sys.dl.BionicDynamicLinker64BitImpl; +import jau.sys.dl.MacOSXDynamicLinkerImpl; +import jau.sys.dl.PosixDynamicLinkerImpl; +import jau.sys.dl.WindowsDynamicLinkerImpl; + +/** Provides low-level, relatively platform-independent access to + shared ("native") libraries. The core library routines + <code>System.load()</code> and <code>System.loadLibrary()</code> + in general provide suitable functionality for applications using + native code, but are not flexible enough to support certain kinds + of glue code generation and deployment strategies. This class + supports direct linking of native libraries to other shared + objects not necessarily installed on the system (in particular, + via the use of dlopen(RTLD_GLOBAL) on Unix platforms) as well as + manual lookup of function names to support e.g. GlueGen's + ProcAddressTable glue code generation style without additional + supporting code needed in the generated library. */ + +public final class NativeLibrary implements DynamicLookupHelper { + private final DynamicLinker dynLink; + + // Platform-specific representation for the handle to the open + // library. This is an HMODULE on Windows and a void* (the result of + // a dlopen() call) on Unix and Mac OS X platforms. + private long libraryHandle; + + // May as well keep around the path to the library we opened + private final String libraryPath; + + private final boolean global; + + // Private constructor to prevent arbitrary instances from floating around + private NativeLibrary(final DynamicLinker dynLink, final long libraryHandle, final String libraryPath, final boolean global) { + this.dynLink = dynLink; + this.libraryHandle = libraryHandle; + this.libraryPath = libraryPath; + this.global = global; + if (DEBUG) { + System.err.println("NativeLibrary.open(): Successfully loaded: " + this); + } + } + + @Override + public final String toString() { + return "NativeLibrary[" + dynLink.getClass().getSimpleName() + ", " + libraryPath + ", 0x" + Long.toHexString(libraryHandle) + ", global " + global + "]"; + } + + /** Opens the given native library, assuming it has the same base + name on all platforms. + <p> + The {@code searchSystemPath} argument changes the behavior to + either use the default system path or not at all. + </p> + <p> + Assuming {@code searchSystemPath} is {@code true}, + the {@code searchSystemPathFirst} argument changes the behavior to first + search the default system path rather than searching it last. + </p> + * @param libName library name, with or without prefix and suffix + * @param searchSystemPath if {@code true} library shall be searched in the system path <i>(default)</i>, otherwise {@code false}. + * @param searchSystemPathFirst if {@code true} system path shall be searched <i>first</i> <i>(default)</i>, rather than searching it last. + * if {@code searchSystemPath} is {@code false} this argument is ignored. + * @param loader {@link ClassLoader} to locate the library + * @param global if {@code true} allows system wide access of the loaded library, otherwise access is restricted to the process. + * @return {@link NativeLibrary} instance or {@code null} if library could not be loaded. + * @throws SecurityException if user is not granted access for the named library. + * @since 2.4.0 + */ + public static final NativeLibrary open(final String libName, + final boolean searchSystemPath, + final boolean searchSystemPathFirst, + final ClassLoader loader, final boolean global) throws SecurityException { + return open(libName, libName, libName, searchSystemPath, searchSystemPathFirst, loader, global); + } + + /** Opens the given native library, assuming it has the given base + names (no "lib" prefix or ".dll/.so/.dylib" suffix) on the + Windows, Unix and Mac OS X platforms, respectively, and in the + context of the specified ClassLoader, which is used to help find + the library in the case of e.g. Java Web Start. + <p> + The {@code searchSystemPath} argument changes the behavior to + either use the default system path or not at all. + </p> + <p> + Assuming {@code searchSystemPath} is {@code true}, + the {@code searchSystemPathFirst} argument changes the behavior to first + search the default system path rather than searching it last. + </p> + Note that we do not currently handle DSO versioning on Unix. + Experience with JOAL and OpenAL has shown that it is extremely + problematic to rely on a specific .so version (for one thing, + ClassLoader.findLibrary on Unix doesn't work with files not + ending in .so, for example .so.0), and in general if this + dynamic loading facility is used correctly the version number + will be irrelevant. + * @param libName windows library name, with or without prefix and suffix + * @param unixLibName unix library name, with or without prefix and suffix + * @param macOSXLibName mac-osx library name, with or without prefix and suffix + * @param searchSystemPath if {@code true} library shall be searched in the system path <i>(default)</i>, otherwise {@code false}. + * @param searchSystemPathFirst if {@code true} system path shall be searched <i>first</i> <i>(default)</i>, rather than searching it last. + * if {@code searchSystemPath} is {@code false} this argument is ignored. + * @param loader {@link ClassLoader} to locate the library + * @param global if {@code true} allows system wide access of the loaded library, otherwise access is restricted to the process. + * @return {@link NativeLibrary} instance or {@code null} if library could not be loaded. + * @throws SecurityException if user is not granted access for the named library. + */ + public static final NativeLibrary open(final String libName, + final String unixLibName, + final String macOSXLibName, + final boolean searchSystemPath, + final boolean searchSystemPathFirst, + final ClassLoader loader, final boolean global) throws SecurityException { + final List<String> possiblePaths = JNILibrary.enumerateLibraryPaths(libName, + unixLibName, + macOSXLibName, + searchSystemPath, searchSystemPathFirst, + loader); + PlatformProps.initSingleton(); // loads native gluegen_rt library + + final DynamicLinker dynLink = getDynamicLinker(); + + // Iterate down these and see which one if any we can actually find. + for (final Iterator<String> iter = possiblePaths.iterator(); iter.hasNext(); ) { + final String path = iter.next(); + if (DEBUG) { + System.err.println("NativeLibrary.open(global "+global+"): Trying to load " + path); + } + long res; + Throwable t = null; + try { + if(global) { + res = dynLink.openLibraryGlobal(path, DEBUG); + } else { + res = dynLink.openLibraryLocal(path, DEBUG); + } + } catch (final Throwable t1) { + t = t1; + res = 0; + } + if ( 0 != res ) { + return new NativeLibrary(dynLink, res, path, global); + } else if( DEBUG ) { + if( null != t ) { + System.err.println("NativeLibrary.open: Caught "+t.getClass().getSimpleName()+": "+t.getMessage()); + } + String errstr; + try { + errstr = dynLink.getLastError(); + } catch (final Throwable t2) { errstr=null; } + System.err.println("NativeLibrary.open: Last error "+errstr); + if( null != t ) { + t.printStackTrace(); + } + } + } + + if (DEBUG) { + System.err.println("NativeLibrary.open(global "+global+"): Did not succeed in loading (" + libName + ", " + unixLibName + ", " + macOSXLibName + ")"); + } + + // For now, just return null to indicate the open operation didn't + // succeed (could also throw an exception if we could tell which + // of the openLibrary operations actually failed) + return null; + } + + @Override + public final void claimAllLinkPermission() throws SecurityException { + dynLink.claimAllLinkPermission(); + } + @Override + public final void releaseAllLinkPermission() throws SecurityException { + dynLink.releaseAllLinkPermission(); + } + + @Override + public final long dynamicLookupFunction(final String funcName) throws SecurityException { + if ( 0 == libraryHandle ) { + throw new RuntimeException("Library is not open"); + } + return dynLink.lookupSymbol(libraryHandle, funcName); + } + + @Override + public final boolean isFunctionAvailable(final String funcName) throws SecurityException { + if ( 0 == libraryHandle ) { + throw new RuntimeException("Library is not open"); + } + return 0 != dynLink.lookupSymbol(libraryHandle, funcName); + } + + /** Looks up the given function name in all loaded libraries. + * @throws SecurityException if user is not granted access for the named library. + */ + public final long dynamicLookupFunctionGlobal(final String funcName) throws SecurityException { + return dynLink.lookupSymbolGlobal(funcName); + } + + /* pp */ final DynamicLinker dynamicLinker() { return dynLink; } + + /* pp */ static DynamicLinker getDynamicLinker() { + final DynamicLinker dynLink; + switch (PlatformProps.OS) { + case WINDOWS: + dynLink = new WindowsDynamicLinkerImpl(); + break; + + case MACOS: + case IOS: + dynLink = new MacOSXDynamicLinkerImpl(); + break; + + case ANDROID: + if( PlatformProps.CPU.is32Bit ) { + dynLink = new BionicDynamicLinker32bitImpl(); + } else { + dynLink = new BionicDynamicLinker64BitImpl(); + } + break; + + default: + dynLink = new PosixDynamicLinkerImpl(); + break; + } + return dynLink; + } + + /** Retrieves the low-level library handle from this NativeLibrary + object. On the Windows platform this is an HMODULE, and on Unix + and Mac OS X platforms the void* result of calling dlopen(). */ + public final long getLibraryHandle() { + return libraryHandle; + } + + /** Retrieves the path under which this library was opened. */ + public final String getLibraryPath() { + return libraryPath; + } + + /** Closes this native library. Further lookup operations are not + allowed after calling this method. + * @throws SecurityException if user is not granted access for the named library. + */ + public final void close() throws SecurityException { + if (DEBUG) { + System.err.println("NativeLibrary.close(): closing " + this); + } + if ( 0 == libraryHandle ) { + throw new RuntimeException("Library already closed"); + } + final long handle = libraryHandle; + libraryHandle = 0; + dynLink.closeLibrary(handle, DEBUG); + if (DEBUG) { + System.err.println("NativeLibrary.close(): Successfully closed " + this); + ExceptionUtils.dumpStack(System.err); + } + } +} |