Skip to content

Commit c525bcd

Browse files
committed
Refactored GC wait loops
1 parent 8512a00 commit c525bcd

File tree

1 file changed

+50
-43
lines changed

1 file changed

+50
-43
lines changed

test/com/sun/jna/CallbacksTest.java

+50-43
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import java.util.List;
3535
import java.util.Map;
3636
import java.util.Set;
37-
import java.util.WeakHashMap;
3837

3938
import com.sun.jna.Callback.UncaughtExceptionHandler;
4039
import com.sun.jna.CallbacksTest.TestLibrary.CbCallback;
@@ -80,6 +79,24 @@ protected void waitFor(Thread thread) {
8079
}
8180
}
8281

82+
public static abstract class Condition<T> {
83+
protected final T obj;
84+
85+
public Condition(T t) { obj = t; }
86+
87+
public boolean evaluate() { return evaluate(obj); }
88+
89+
abstract boolean evaluate(T t);
90+
}
91+
protected static void waitForGc(Condition<?> condition) throws Exception {
92+
for (int i = 0; i < 2 * Cleaner.MASTER_CLEANUP_INTERVAL_MS / 10 + 5 && condition.evaluate(); ++i) {
93+
synchronized (CallbacksTest.class) { // cleanups happen in a different thread, make sure we see it here
94+
System.gc();
95+
}
96+
Thread.sleep(10); // Give the GC a chance to run
97+
}
98+
}
99+
83100
public static class SmallTestStructure extends Structure {
84101
public static final List<String> FIELDS = createFieldsOrder("value");
85102
public double value;
@@ -355,31 +372,26 @@ public void callback() {
355372
lib.callVoidCallback(cb);
356373
assertTrue("Callback not called", called[0]);
357374

358-
Map<Callback, CallbackReference> refs = new WeakHashMap<>(callbackCache());
359-
assertTrue("Callback not cached", refs.containsKey(cb));
375+
assertTrue("Callback not cached", callbackCache().containsKey(cb));
376+
final Map<Callback, CallbackReference> refs = callbackCache();
360377
CallbackReference ref = refs.get(cb);
361-
refs = callbackCache();
362-
Pointer cbstruct = ref.cbstruct;
378+
final Pointer cbstruct = ref.cbstruct;
363379

364380
cb = null;
365-
System.gc();
366-
for (int i = 0; i < Cleaner.MASTER_CLEANUP_INTERVAL_MS / 10 + 5 && (ref.get() != null || refs.containsValue(ref)); ++i) {
367-
Thread.sleep(10); // Give the GC a chance to run
368-
System.gc();
369-
}
381+
waitForGc(new Condition<CallbackReference>(ref) {
382+
public boolean evaluate(CallbackReference _ref) {
383+
return _ref.get() != null || refs.containsValue(_ref);
384+
}
385+
});
370386
assertNull("Callback not GC'd", ref.get());
371387
assertFalse("Callback still in map", refs.containsValue(ref));
372388

373389
ref = null;
374-
System.gc();
375-
for (int i = 0; i < Cleaner.MASTER_CLEANUP_INTERVAL_MS / 10 + 5 && (cbstruct.peer != 0 || refs.size() > 0); ++i) {
376-
// Flush weak hash map
377-
refs.size();
378-
Thread.sleep(10); // Give the GC a chance to run
379-
synchronized (CallbacksTest.class) { // the cbstruct.peer cleanup happens in a different thread, make sure we see it here
380-
System.gc();
390+
waitForGc(new Condition<Object>(null) {
391+
public boolean evaluate(Object o) {
392+
return refs.size() > 0 || cbstruct.peer != 0;
381393
}
382-
}
394+
});
383395
assertEquals("Callback trampoline not freed", 0, cbstruct.peer);
384396
}
385397

@@ -679,7 +691,7 @@ public String callback(String arg, String arg2) {
679691
assertEquals("Wrong String return", VALUE + VALUE2, value);
680692
}
681693

682-
public void testStringCallbackMemoryReclamation() throws InterruptedException {
694+
public void testStringCallbackMemoryReclamation() throws Exception {
683695
TestLibrary.StringCallback cb = new TestLibrary.StringCallback() {
684696
@Override
685697
public String callback(String arg, String arg2) {
@@ -688,24 +700,22 @@ public String callback(String arg, String arg2) {
688700
};
689701

690702
// A little internal groping
691-
Map<?, ?> m = CallbackReference.allocations;
703+
final Map<?, ?> m = CallbackReference.allocations;
692704
m.clear();
693705

694706
Charset charset = Charset.forName(Native.getDefaultStringEncoding());
695707
String arg = getName() + "1" + charset.decode(charset.encode(UNICODE));
696708
String arg2 = getName() + "2" + charset.decode(charset.encode(UNICODE));
697709
String value = lib.callStringCallback(cb, arg, arg2);
698-
WeakReference<Object> ref = new WeakReference<>(value);
710+
final WeakReference<Object> ref = new WeakReference<>(value);
699711

700712
arg = null;
701713
value = null;
702-
System.gc();
703-
for (int i = 0; i < 100 && (ref.get() != null || m.size() > 0); ++i) {
704-
try {
705-
Thread.sleep(10); // Give the GC a chance to run
706-
System.gc();
707-
} finally {}
708-
}
714+
waitForGc(new Condition<Object>(null) {
715+
public boolean evaluate(Object o) {
716+
return m.size() > 0 || ref.get() != null;
717+
}
718+
});
709719
assertNull("NativeString reference not GC'd", ref.get());
710720
assertEquals("NativeString reference still held: " + m.values(), 0, m.size());
711721
}
@@ -1478,30 +1488,27 @@ public void callback() {
14781488
assertEquals("Wrong module HANDLE for DLL function pointer", handle, pref.getValue());
14791489

14801490
// Check slot re-use
1481-
Map<Callback, CallbackReference> refs = new WeakHashMap<>(callbackCache());
1482-
assertTrue("Callback not cached", refs.containsKey(cb));
1491+
assertTrue("Callback not cached", callbackCache().containsKey(cb));
1492+
final Map<Callback, CallbackReference> refs = callbackCache();
14831493
CallbackReference ref = refs.get(cb);
1484-
refs = callbackCache();
14851494
Pointer cbstruct = ref.cbstruct;
14861495
Pointer first_fptr = cbstruct.getPointer(0);
14871496

14881497
cb = null;
1489-
System.gc();
1490-
for (int i = 0; i < 100 && (ref.get() != null || refs.containsValue(ref)); ++i) {
1491-
Thread.sleep(10); // Give the GC a chance to run
1492-
System.gc();
1493-
}
1498+
waitForGc(new Condition<CallbackReference>(ref) {
1499+
public boolean evaluate(CallbackReference _ref) {
1500+
return _ref.get() != null || refs.containsValue(_ref);
1501+
}
1502+
});
14941503
assertNull("Callback not GC'd", ref.get());
14951504
assertFalse("Callback still in map", refs.containsValue(ref));
14961505

14971506
ref = null;
1498-
System.gc();
1499-
for (int i = 0; i < 100 && (cbstruct.peer != 0 || refs.size() > 0); ++i) {
1500-
// Flush weak hash map
1501-
refs.size();
1502-
Thread.sleep(10); // Give the GC a chance to run
1503-
System.gc();
1504-
}
1507+
waitForGc(new Condition<Pointer>(cbstruct) {
1508+
public boolean evaluate(Pointer p) {
1509+
return refs.size() > 0 || p.peer != 0;
1510+
}
1511+
});
15051512
assertEquals("Callback trampoline not freed", 0, cbstruct.peer);
15061513

15071514
// Next allocation should be at same place

0 commit comments

Comments
 (0)