3434import java .util .List ;
3535import java .util .Map ;
3636import java .util .Set ;
37- import java .util .WeakHashMap ;
3837
3938import com .sun .jna .Callback .UncaughtExceptionHandler ;
4039import 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