Native Scheduling Support

The Java threading API that we’ve examined so far is somewhat incomplete for certain advanced scheduling uses. For example, there is no way to tell how many CPUs a machine has, or to set the number of LWPs that you want your Solaris virtual machine to have, or to set processor affinity masks so that certain threads run on certain processors. Unfortunately, the only way to overcome these limitations is to introduce native methods calls into your program.

We’ll show just the basic outline of how to do that for certain calls in this section. We’ll give a complete example, but the full details of Windows threads, Solaris or POSIX threads, and the Java native interface ( JNI) are beyond the scope of this book.

We’ll start with a class that allows us to perform three operations: getting the number of CPUs on the machine and getting and setting the number of threads that we want the virtual machine to be able to run concurrently:

public class CPUSupport {
    static boolean loaded = false;
    static {
        try {
            System.loadLibrary("CPUSupportWin");
            loaded = true;
        } catch (Error e) {
            try {
            System.loadLibrary("CPUSupportSolaris");
                loaded = true;
            } catch (Error err) {
                System.err.println(
                        "Warning: No platform library for CPUSupport");
            }
        }
    }

    private static native int getConcurrencyN();
    private static native void setConcurrencyN(int i);
    private static native int getNumProcessorsN();

    public static int getConcurrency() {
        if (!loaded)
            // Assume green threads.
            return 1;
        return getConcurrencyN();
    }

    public static void setConcurrency(int n) {
        if (loaded)
            setConcurrencyN(n);
    }

    public static int getNumProcessors() {
        if (!loaded)
            // Assume green threads.
            return 1;
        return getNumProcessorsN();
    }
}

We’ve designed this class so that it will work on all platforms; if there is no platform-specific native library available, we’ll assume the green-thread model. Of course, this can be easily adapted to include support for other operating systems if desired. Now all we need to do is to write the specific native library for the platforms that we want to support.

Implementing CPUSupport on Windows

Here’s the code that implements the native library for Windows:

#include <jni.h>
#include <windows.h>

JNIEXPORT jint JNICALL Java_CPUSupport_getNumProcessorsN
                        (JNIEnv *env, jobject cls)
{
    static DWORD numCPU = 0;
    SYSTEM_INFO process_info;

    if (numCPU == 0) {
        GetSystemInfo(&process_info);
        numCPU = process_info.dwNumberOfProcessors;
    }
    return numCPU;
}

JNIEXPORT void JNICALL Java_CPUSupport_setConcurrencyN
                        (JNIEnv *env, jobject cls, jint kthreads)
{
    // For Windows the concurrency is always infinity.
    return;
}

JNIEXPORT jint JNICALL Java_CPUSupport_getConcurrencyN
                        (JNIEnv *env, jobject cls)
{
    // For Windows the concurrency is always infinity, but
    // we will return the number of processors instead.
    return Java_CPUSupport_getNumProcessorsN(env, cls);
}

To obtain the number of CPUs on Windows, we simply use the operating system’s GetSystemInfo() function and extract the desired information. However, we’re not able to affect the concurrency of threads on Windows: each Java thread is assigned to its own Windows thread. This leads to an effective concurrency of infinity (given an infinite amount of memory and CPU speed). So we return the number of processors instead, which gives us an idea of how many threads can run simultaneously.

To compile this code with the Microsoft C/C++ 5.0 compiler, execute this command:

cl -Ic:javainclude -Ic:javaincludewin32 -LD CPUSupportWin.c

You’ll need to substitute the appropriate directory path for c:java depending upon where your JDK is installed. The resulting DLL file (CPUSupportWin.dll ) must be located in the PATH environment for the virtual machine to find it.

Implementing CPUSupport on Solaris

Here’s the code required to support the CPUSupport class on Solaris:

#include <jni.h>
#include <thread.h>

JNIEXPORT jint JNICALL Java_CPUSupport_getConcurrencyN
            (JNIEnv * env, jobject class)
{
    return thr_getconcurrency();
}

JNIEXPORT void JNICALL Java_CPUSupport_setConcurrencyN
            (JNIEnv * env, jobject class, jint n)
{
    thr_setconcurrency(n);
}

JNIEXPORT jint JNICALL Java_CPUSupport_getNumProcessorsN
            (JNIEnv * env, jobject class)
{
    int num_threads;
    num_threads = sysconf(_SC_NPROCESSORS_ONLN);
    return num_threads;
}

Again, the implementation is predictably simple because it maps to operating system function calls. In this case, the getConcurrency() method will return the current number of LWPs, and the setConcurrency() method will set the current number of LWPs.

To compile this library with the Sun Workshop 4.2 C compiler, execute this command:

cc -I/usr/java/include -I/usr/java/include/solaris -mt -G -o 
libCPUSupportSolaris.so CPUSupportSolaris.c

If your JDK is installed in a place other than /usr/java, change that pathname accordingly. Once the library is compiled, you must add it to your LD_LIBRARY_PATH environment in order for the virtual machine to find it.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset