Author: nextgens
Date: 2008-02-15 04:33:30 +0000 (Fri, 15 Feb 2008)
New Revision: 17908
Added:
trunk/freenet/src/freenet/support/io/NativeThread.java
Log:
NativeThread: the Java part of the niceing kludge
Added: trunk/freenet/src/freenet/support/io/NativeThread.java
===================================================================
--- trunk/freenet/src/freenet/support/io/NativeThread.java
(rev 0)
+++ trunk/freenet/src/freenet/support/io/NativeThread.java 2008-02-15
04:33:30 UTC (rev 17908)
@@ -0,0 +1,143 @@
+/* This code is part of Freenet. It is distributed under the GNU General
+ * Public License, version 2 (or at your option any later version). See
+ * http://www.gnu.org/ for further details of the GPL. */
+
+package freenet.support.io;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.net.URL;
+
+/**
+ * @author Florent Daignière <nextgens at freenetproject.org>
+ */
+public class NativeThread extends Thread {
+ private static boolean _loadNative;
+ private static final int JAVA_PRIO_RANGE = MAX_PRIORITY - MIN_PRIORITY;
+ private static final int NATIVE_PRIORITY_BASE;
+ private static final int NATIVE_PRIORITY_RANGE;
+ private int currentPriority = Thread.MAX_PRIORITY;
+
+ public static final boolean HAS_THREE_NICE_LEVELS;
+ public static final boolean HAS_ENOUGH_NICE_LEVELS;
+
+ static {
+ _loadNative =
"Linux".equalsIgnoreCase(System.getProperty("os.name"));
+ if(_loadNative) {
+ //System.loadLibrary("NativeThread");
+ loadNative();
+ NATIVE_PRIORITY_BASE = getLinuxPriority();
+ NATIVE_PRIORITY_RANGE = 19 - NATIVE_PRIORITY_BASE;
+ System.out.println("Using the NativeThread
implementation (base nice level is "+NATIVE_PRIORITY_BASE+')');
+ // they are 3 main prio levels
+ HAS_THREE_NICE_LEVELS = NATIVE_PRIORITY_RANGE >= 3;
+ HAS_ENOUGH_NICE_LEVELS = NATIVE_PRIORITY_RANGE
>=JAVA_PRIO_RANGE;
+ if(!(HAS_ENOUGH_NICE_LEVELS && HAS_THREE_NICE_LEVELS))
+ System.err.println("WARNING!!! The JVM has been
niced down to a level which won't allow it to schedule threads properly! LOWER
THE NICE LEVEL!!");
+ } else {
+ // unused anyway
+ NATIVE_PRIORITY_BASE = 0;
+ NATIVE_PRIORITY_RANGE = 19;
+ HAS_THREE_NICE_LEVELS = true;
+ HAS_ENOUGH_NICE_LEVELS = true;
+ }
+ }
+
+ private static void loadNative() {
+ // System.loadLibrary("NativeThread");
+ String arch;
+
if(System.getProperty("os.arch").toLowerCase().matches("(i?[x0-9]86_64|amd64)"))
{
+ arch = "amd64";
+ } else
if(System.getProperty("os.arch").toLowerCase().matches("(ppc)")) {
+ arch = "ppc";
+ } else {
+ arch = "i386";
+ }
+
+ String resourceName = "/freenet/support/io/libNativeThread-" +
arch + ".so";
+ try {
+ System.out.println("ok");
+ // Get the resource
+ URL resource =
NativeThread.class.getResource(resourceName);
+
+ // Get input stream from jar resource
+ InputStream inputStream = resource.openStream();
+
+ // Copy resource to filesystem in a temp folder with a
unique name
+ File temporaryLib =
File.createTempFile("libNativeThread", ".so");
+
+ // Delete on exit the dll
+ temporaryLib.deleteOnExit();
+
+ FileOutputStream outputStream = new
FileOutputStream(temporaryLib);
+ byte[] array = new byte[2048];
+ int read = 0;
+ while((read = inputStream.read(array)) > 0) {
+ outputStream.write(array, 0, read);
+ }
+ outputStream.close();
+
+ // Finally, load the dll
+ System.out.println("Attempting to load the NativeThread
library ["+resource+']');
+ System.load(temporaryLib.getPath());
+ } catch(Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ public NativeThread(Runnable r, String name, int priority) {
+ super(r, name);
+ this.currentPriority = priority;
+ }
+
+ public NativeThread(ThreadGroup g, Runnable r, String name, int
priority) {
+ super(g, r, name);
+ this.currentPriority = priority;
+ }
+
+ /**
+ * Set linux priority (JNI call)
+ *
+ * @return true if successful, false otherwise.
+ */
+ private static native boolean setLinuxPriority(int prio);
+
+ /**
+ * Get linux priority (JNI call)
+ */
+ private static native int getLinuxPriority();
+
+ public void run() {
+ if(!setNativePriority(currentPriority))
+
System.err.println("setNativePriority("+currentPriority+") has failed!");
+ super.run();
+ }
+
+ /**
+ * Rescale java priority and set linux priority.
+ */
+ private boolean setNativePriority(int prio) {
+ setPriority(prio);
+ if(!_loadNative) return true;
+ System.out.println(getLinuxPriority());
+ if(NATIVE_PRIORITY_BASE != getLinuxPriority()) {
+ /* The user has reniced freenet or we didn't use the
PacketSender to create the thread
+ * either ways it's bad for us.
+ *
+ * Let's diable the renicing as we can't rely on it
anymore.
+ */
+ _loadNative = false;
+ System.err.println("Freenet has detected it has been
reniced : THAT'S BAD, DON'T DO IT!");
+ return false;
+ }
+ final int linuxPriority = NATIVE_PRIORITY_BASE +
NATIVE_PRIORITY_RANGE - (NATIVE_PRIORITY_RANGE * (prio - MIN_PRIORITY)) /
JAVA_PRIO_RANGE;
+ // That's an obvious coding mistake
+ if(prio < currentPriority)
+ throw new IllegalStateException("You're trying to set a
thread priority" +
+ " above the current value!! It's not possible
if you aren't root" +
+ " and shouldn't ever occur in our code.
(asked="+prio+':'+linuxPriority+" currentMax="+
+ +currentPriority+':'+NATIVE_PRIORITY_BASE+")
SHOUDLN'T HAPPEN, please report!");
+ return setLinuxPriority(linuxPriority);
+ }
+}