Pointer handle = f.invokePointer(new Object[] { Native.jnidispatchPath != null ? Native.jnidispatchPath : "jnidispatch" });
assertNotNull("GetModuleHandle(\"jnidispatch\") failed: " + Native.getLastError(), handle);
assertEquals("Wrong module HANDLE for DLL function pointer", handle, pref.getValue());
// Check slot re-use
Map refs = new WeakHashMap(callbackCache());
assertTrue("Callback not cached", refs.containsKey(cb));
CallbackReference ref = (CallbackReference)refs.get(cb);
refs = callbackCache();
Pointer cbstruct = ref.cbstruct;
Pointer first_fptr = cbstruct.getPointer(0);
cb = null;
System.gc();
for (int i = 0; i < 100 && (ref.get() != null || refs.containsValue(ref)); ++i) {
Thread.sleep(10); // Give the GC a chance to run
System.gc();
}
assertNull("Callback not GC'd", ref.get());
assertFalse("Callback still in map", refs.containsValue(ref));
ref = null;
System.gc();
for (int i = 0; i < 100 && (cbstruct.peer != 0 || refs.size() > 0); ++i) {
// Flush weak hash map
refs.size();
Thread.sleep(10); // Give the GC a chance to run
System.gc();
}
assertEquals("Callback trampoline not freed", 0, cbstruct.peer);
// Next allocation should be at same place
called[0] = false;
cb = new TestCallback();
lib.callVoidCallback(cb);
ref = (CallbackReference)refs.get(cb);
cbstruct = ref.cbstruct;
assertTrue("Callback not called", called[0]);
assertEquals("Same (in-DLL) address should be re-used for DLL callbacks after callback is GCd",
first_fptr, cbstruct.getPointer(0));