[freenet-cvs] r17908 - trunk/freenet/src/freenet/support/io

nextgens at freenetproject.org nextgens at freenetproject.org
Fri Feb 15 04:33:30 UTC 2008


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);
+	}
+}




More information about the cvs mailing list