34
34
import java .util .List ;
35
35
import java .util .Map ;
36
36
import java .util .Set ;
37
- import java .util .WeakHashMap ;
38
37
39
38
import com .sun .jna .Callback .UncaughtExceptionHandler ;
40
39
import com .sun .jna .CallbacksTest .TestLibrary .CbCallback ;
@@ -80,6 +79,24 @@ protected void waitFor(Thread thread) {
80
79
}
81
80
}
82
81
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
+
83
100
public static class SmallTestStructure extends Structure {
84
101
public static final List <String > FIELDS = createFieldsOrder ("value" );
85
102
public double value ;
@@ -355,31 +372,26 @@ public void callback() {
355
372
lib .callVoidCallback (cb );
356
373
assertTrue ("Callback not called" , called [0 ]);
357
374
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 ( );
360
377
CallbackReference ref = refs .get (cb );
361
- refs = callbackCache ();
362
- Pointer cbstruct = ref .cbstruct ;
378
+ final Pointer cbstruct = ref .cbstruct ;
363
379
364
380
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
+ });
370
386
assertNull ("Callback not GC'd" , ref .get ());
371
387
assertFalse ("Callback still in map" , refs .containsValue (ref ));
372
388
373
389
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 ;
381
393
}
382
- }
394
+ });
383
395
assertEquals ("Callback trampoline not freed" , 0 , cbstruct .peer );
384
396
}
385
397
@@ -679,7 +691,7 @@ public String callback(String arg, String arg2) {
679
691
assertEquals ("Wrong String return" , VALUE + VALUE2 , value );
680
692
}
681
693
682
- public void testStringCallbackMemoryReclamation () throws InterruptedException {
694
+ public void testStringCallbackMemoryReclamation () throws Exception {
683
695
TestLibrary .StringCallback cb = new TestLibrary .StringCallback () {
684
696
@ Override
685
697
public String callback (String arg , String arg2 ) {
@@ -688,24 +700,22 @@ public String callback(String arg, String arg2) {
688
700
};
689
701
690
702
// A little internal groping
691
- Map <?, ?> m = CallbackReference .allocations ;
703
+ final Map <?, ?> m = CallbackReference .allocations ;
692
704
m .clear ();
693
705
694
706
Charset charset = Charset .forName (Native .getDefaultStringEncoding ());
695
707
String arg = getName () + "1" + charset .decode (charset .encode (UNICODE ));
696
708
String arg2 = getName () + "2" + charset .decode (charset .encode (UNICODE ));
697
709
String value = lib .callStringCallback (cb , arg , arg2 );
698
- WeakReference <Object > ref = new WeakReference <>(value );
710
+ final WeakReference <Object > ref = new WeakReference <>(value );
699
711
700
712
arg = null ;
701
713
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
+ });
709
719
assertNull ("NativeString reference not GC'd" , ref .get ());
710
720
assertEquals ("NativeString reference still held: " + m .values (), 0 , m .size ());
711
721
}
@@ -1478,30 +1488,27 @@ public void callback() {
1478
1488
assertEquals ("Wrong module HANDLE for DLL function pointer" , handle , pref .getValue ());
1479
1489
1480
1490
// 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 ( );
1483
1493
CallbackReference ref = refs .get (cb );
1484
- refs = callbackCache ();
1485
1494
Pointer cbstruct = ref .cbstruct ;
1486
1495
Pointer first_fptr = cbstruct .getPointer (0 );
1487
1496
1488
1497
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
+ });
1494
1503
assertNull ("Callback not GC'd" , ref .get ());
1495
1504
assertFalse ("Callback still in map" , refs .containsValue (ref ));
1496
1505
1497
1506
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
+ });
1505
1512
assertEquals ("Callback trampoline not freed" , 0 , cbstruct .peer );
1506
1513
1507
1514
// Next allocation should be at same place
0 commit comments