Changed NativeLibraryLocator to make extraction code multi-process safe.
This commit is contained in:
@@ -75,10 +75,16 @@ Some sample code to use the terminal:
|
|||||||
|
|
||||||
## Changes
|
## Changes
|
||||||
|
|
||||||
|
### 0.2
|
||||||
|
|
||||||
|
Fixes to make native library extraction multi-process safe.
|
||||||
|
|
||||||
### 0.1
|
### 0.1
|
||||||
|
|
||||||
Initial release
|
Initial release
|
||||||
|
|
||||||
|
# Development
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
You will need to use the Gradle wrapper. Just run `gradlew` in the root directory.
|
You will need to use the Gradle wrapper. Just run `gradlew` in the root directory.
|
||||||
@@ -174,7 +180,6 @@ You can run `$INSTALL_DIR/bin/native-platform-test` to run the test application.
|
|||||||
* String names for errno values.
|
* String names for errno values.
|
||||||
* Split into multiple projects.
|
* Split into multiple projects.
|
||||||
* Convert to c.
|
* Convert to c.
|
||||||
* Make native library extraction multi-process safe.
|
|
||||||
* Use fully decomposed form for unicode file names on hfs+ filesystems.
|
* Use fully decomposed form for unicode file names on hfs+ filesystems.
|
||||||
* Extend FileSystem to deal with removable media.
|
* Extend FileSystem to deal with removable media.
|
||||||
|
|
||||||
|
|||||||
@@ -19,22 +19,17 @@ public class Native {
|
|||||||
private Native() {
|
private Native() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the version of the native library implementations used by this class.
|
|
||||||
*/
|
|
||||||
@ThreadSafe
|
|
||||||
static public String getNativeVersion() {
|
|
||||||
return String.valueOf(NativeLibraryFunctions.VERSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialises the native integration, if not already initialized.
|
* Initialises the native integration, if not already initialized.
|
||||||
*
|
*
|
||||||
* @param extractDir The directory to extract native resources into. May be null, in which case a default is
|
* @param extractDir The directory to extract native resources into. May be null, in which case a default is
|
||||||
* selected.
|
* selected.
|
||||||
|
*
|
||||||
|
* @throws NativeIntegrationUnavailableException When native integration is not available on the current machine.
|
||||||
|
* @throws NativeException On failure to load the native integration.
|
||||||
*/
|
*/
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
static public void init(File extractDir) {
|
static public void init(File extractDir) throws NativeIntegrationUnavailableException, NativeException {
|
||||||
synchronized (Native.class) {
|
synchronized (Native.class) {
|
||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
Platform platform = Platform.current();
|
Platform platform = Platform.current();
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package net.rubygrapefruit.platform.internal;
|
package net.rubygrapefruit.platform.internal;
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
import net.rubygrapefruit.platform.NativeException;
|
||||||
|
import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.nio.channels.FileLock;
|
||||||
|
|
||||||
public class NativeLibraryLocator {
|
public class NativeLibraryLocator {
|
||||||
private final File extractDir;
|
private final File extractDir;
|
||||||
@@ -13,22 +15,47 @@ public class NativeLibraryLocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public File find(String libraryName) throws IOException {
|
public File find(String libraryName) throws IOException {
|
||||||
File libFile;
|
if (extractDir != null) {
|
||||||
|
File libFile = new File(extractDir, String.format("%s/%s", NativeLibraryFunctions.VERSION, libraryName));
|
||||||
|
File lockFile = new File(libFile.getParentFile(), libFile.getName() + ".lock");
|
||||||
|
lockFile.getParentFile().mkdirs();
|
||||||
|
lockFile.createNewFile();
|
||||||
|
RandomAccessFile lockFileAccess = new RandomAccessFile(lockFile, "rw");
|
||||||
|
try {
|
||||||
|
// Take exclusive lock on lock file
|
||||||
|
FileLock lock = lockFileAccess.getChannel().lock();
|
||||||
|
if (lockFile.length() > 0 && lockFileAccess.readBoolean()) {
|
||||||
|
// Library has been extracted
|
||||||
|
return libFile;
|
||||||
|
}
|
||||||
URL resource = getClass().getClassLoader().getResource(libraryName);
|
URL resource = getClass().getClassLoader().getResource(libraryName);
|
||||||
if (resource != null) {
|
if (resource != null) {
|
||||||
File libDir = extractDir;
|
// Extract library and write marker to lock file
|
||||||
if (libDir == null) {
|
libFile.getParentFile().mkdirs();
|
||||||
libDir = File.createTempFile("native-platform", "dir");
|
copy(resource, libFile);
|
||||||
|
lockFileAccess.seek(0);
|
||||||
|
lockFileAccess.writeBoolean(true);
|
||||||
|
return libFile;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// Also releases lock
|
||||||
|
lockFileAccess.close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
URL resource = getClass().getClassLoader().getResource(libraryName);
|
||||||
|
if (resource != null) {
|
||||||
|
File libFile;
|
||||||
|
File libDir = File.createTempFile("native-platform", "dir");
|
||||||
libDir.delete();
|
libDir.delete();
|
||||||
libDir.mkdirs();
|
libDir.mkdirs();
|
||||||
}
|
|
||||||
libFile = new File(libDir, libraryName);
|
libFile = new File(libDir, libraryName);
|
||||||
libFile.deleteOnExit();
|
libFile.deleteOnExit();
|
||||||
copy(resource, libFile);
|
copy(resource, libFile);
|
||||||
return libFile;
|
return libFile;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
libFile = new File("build/binaries/" + libraryName);
|
File libFile = new File("build/binaries/" + libraryName);
|
||||||
if (libFile.isFile()) {
|
if (libFile.isFile()) {
|
||||||
return libFile;
|
return libFile;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ if (project.hasProperty('release')) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile 'net.sf.jopt-simple:jopt-simple:4.2'
|
||||||
|
}
|
||||||
|
|
||||||
configurations.archives.artifacts.clear()
|
configurations.archives.artifacts.clear()
|
||||||
artifacts {
|
artifacts {
|
||||||
archives distZip
|
archives distZip
|
||||||
|
|||||||
@@ -1,10 +1,33 @@
|
|||||||
package net.rubygrapefruit.platform.test;
|
package net.rubygrapefruit.platform.test;
|
||||||
|
|
||||||
|
import joptsimple.OptionException;
|
||||||
|
import joptsimple.OptionParser;
|
||||||
|
import joptsimple.OptionSet;
|
||||||
import net.rubygrapefruit.platform.*;
|
import net.rubygrapefruit.platform.*;
|
||||||
import net.rubygrapefruit.platform.Process;
|
import net.rubygrapefruit.platform.Process;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) throws IOException {
|
||||||
|
OptionParser optionParser = new OptionParser();
|
||||||
|
optionParser.accepts("cache-dir", "The directory to cache native libraries in").withRequiredArg();
|
||||||
|
|
||||||
|
OptionSet result = null;
|
||||||
|
try {
|
||||||
|
result = optionParser.parse(args);
|
||||||
|
} catch (OptionException e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
System.err.println();
|
||||||
|
optionParser.printHelpOn(System.err);
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.has("cache-dir")) {
|
||||||
|
Native.init(new File(result.valueOf("cache-dir").toString()));
|
||||||
|
}
|
||||||
|
|
||||||
System.out.println();
|
System.out.println();
|
||||||
System.out.println("* OS: " + System.getProperty("os.name") + ' ' + System.getProperty("os.version") + ' ' + System.getProperty("os.arch"));
|
System.out.println("* OS: " + System.getProperty("os.name") + ' ' + System.getProperty("os.version") + ' ' + System.getProperty("os.arch"));
|
||||||
System.out.println("* JVM: " + System.getProperty("java.vm.vendor") + ' ' + System.getProperty("java.version"));
|
System.out.println("* JVM: " + System.getProperty("java.vm.vendor") + ' ' + System.getProperty("java.version"));
|
||||||
|
|||||||
Reference in New Issue
Block a user