Decision when to load 64bit?

Started by mstWeal, September 12, 2010, 18:56:07

Previous topic - Next topic

mstWeal

Hi there,

how does LWJGL determine when to load the 64bit DLLs and when to load the 32bit DLLs?

For I have a 64bit system. So far everything worked fine but I started to use PowerMock to write my unit tests. Curiously, if I start unit tests with the PowerMock test runner there is an unsatisfied exception, stating that 32bit DLLs cannot be loaded on AMD 64 bit processors. I removed the 32bit DLLs but then it complains that lwjgl.dll cannot be found ...

Matzon

Sys.java:
    private static void loadLibrary(final String lib_name) {
        try {
            doLoadLibrary(lib_name);
        } catch (UnsatisfiedLinkError e) {
            if (implementation.has64Bit()) {
                try {
                    doLoadLibrary(lib_name + POSTFIX64BIT);
                    return;
                } catch (UnsatisfiedLinkError e2) {
                    LWJGLUtil.log("Failed to load 64 bit library: " + e2.getMessage());
                }
            }
            // Throw original error
            throw e;
        }
    }


one could argue that if 64 bit is available for the implementation it would try that first.

something similar to this:
    private static void loadLibrary(final String lib_name) {
        if (implementation.has64Bit()) {
            try {
                doLoadLibrary(lib_name + POSTFIX64BIT);
                return;
            } catch (UnsatisfiedLinkError e2) {
                LWJGLUtil.log("Failed to load 64 bit library: " + e2.getMessage());
            }
        }
        try {
            doLoadLibrary(lib_name);
        } catch (UnsatisfiedLinkError e) {
            // Throw original error
            throw e;
        }
    }

mstWeal

Okay thank you. I've debugged into that code and the source of the exception says the following:

"Native Library E:\Dokumente\Workspace\lib\lwjgl\native\windows\lwjgl64.dll already loaded in another classloader"

Well that explains why the test works if I only run the PowerMock test alone but not when I run all my tests together. PowerMock uses it's own class loader and then this leads to this situation. Is it possible to "fix" this at LWJGL level?

Matzon

I dont think we'd want to support this on a lwjgl level - not sure...

however the appletload has an 'unloadNatives' method that kappa added to fix this issue for applet. You may be able to use this.

    /**
     * Unload natives loaded by a different classloader.
     * 
     * Due to limitations of the jvm, native files can only 
     * be loaded once and only be used by the classloader 
     * they were loaded from.
     * 
     * Due to the way applets on plugin1 work, one jvm must
     * be used for all applets. We need to use multiple 
     * classloaders in the same jvm due to LWJGL's static 
     * nature. I order to solve this we simply remove the 
     * natives from a previous classloader allowing a new 
     * classloader to use those natives in the same jvm.
     * 
     * This method will only attempt to unload natives from a
     * previous classloader if it detects that the natives have
     * been loaded in the same jvm.
     * 
     * @param nativePath directory where natives are stored
     */
    private void unloadNatives(String nativePath) {
        
        // check whether natives have been loaded into this jvm
        if (!natives_loaded) {
            return;
        }
        
        try {
            Field field = ClassLoader.class.getDeclaredField("loadedLibraryNames");
            field.setAccessible(true);
            Vector libs = (Vector) field.get(getClass().getClassLoader());
            
            String path = new File(nativePath).getCanonicalPath();
            
            for (int i = 0; i < libs.size(); i++) {
                String s = (String) libs.get(i);
                
                // if a native from the nativePath directory is loaded, unload it
                if (s.startsWith(path)) {
                    libs.remove(i);
                    i--;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

mstWeal

Thank you, this should workaround the problem for me as I will be able to unload the libraries in the tearDown method of the test cases :-)