6992968: test/java/lang/management/MemoryMXBean/CollectionUsageThresholdConcMarkSweepGC.sh should not hang
authormchung
Tue, 19 Oct 2010 09:49:08 -0700
changeset 7019 f2f6b61d34ac
parent 6907 932cbb0eed6b
child 7020 25638687fe82
6992968: test/java/lang/management/MemoryMXBean/CollectionUsageThresholdConcMarkSweepGC.sh should not hang Reviewed-by: alanb, dholmes
jdk/test/java/lang/management/MemoryMXBean/CollectionUsageThreshold.java
jdk/test/java/lang/management/MemoryMXBean/CollectionUsageThresholdConcMarkSweepGC.sh
--- a/jdk/test/java/lang/management/MemoryMXBean/CollectionUsageThreshold.java	Mon Oct 18 18:04:02 2010 +0100
+++ b/jdk/test/java/lang/management/MemoryMXBean/CollectionUsageThreshold.java	Tue Oct 19 09:49:08 2010 -0700
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug     4959889
+ * @bug     4959889 6992968
  * @summary Basic unit test of memory management testing:
  *          1) setCollectionUsageThreshold() and getCollectionUsageThreshold()
  *          2) test notification emitted for two different memory pools.
@@ -34,8 +34,10 @@
  * @run main/timeout=300 CollectionUsageThreshold
  */
 
+import java.lang.Thread.*;
 import java.lang.management.*;
 import java.util.*;
+import java.util.concurrent.*;
 import javax.management.*;
 import javax.management.openmbean.CompositeData;
 
@@ -52,6 +54,12 @@
     private static Checker checker;
     private static int numGCs = 0;
 
+    // semaphore to signal the arrival of a low memory notification
+    private static Semaphore signals = new Semaphore(0);
+    // barrier for the main thread to wait until the checker thread
+    // finishes checking the low memory notification result
+    private static CyclicBarrier barrier = new CyclicBarrier(2);
+
     static class PoolRecord {
         private MemoryPoolMXBean pool;
         private int listenerInvoked = 0;
@@ -98,10 +106,9 @@
                 }
                 pr.addNotification(minfo);
                 synchronized (this) {
+                    System.out.println("notifying the checker thread to check result");
                     numNotifs++;
-                    if (numNotifs > 0 && (numNotifs % EXPECTED_NUM_POOLS) == 0) {
-                        checker.goCheckResult();
-                    }
+                    signals.release();
                 }
             }
         }
@@ -134,6 +141,9 @@
         }
 
         try {
+            // This test creates a checker thread responsible for checking
+            // the low memory notifications.  It blocks until a permit
+            // from the signals semaphore is available.
             checker = new Checker("Checker thread");
             checker.setDaemon(true);
             checker.start();
@@ -148,9 +158,18 @@
             NotificationEmitter emitter = (NotificationEmitter) mm;
             emitter.addNotificationListener(listener, null, null);
 
+            // The main thread invokes GC to trigger the VM to perform
+            // low memory detection and then waits until the checker thread
+            // finishes its work to check for a low-memory notification.
+            //
+            // At GC time, VM will issue low-memory notification and invoke
+            // the listener which will release a permit to the signals semaphore.
+            // When the checker thread acquires the permit and finishes
+            // checking the low-memory notification, it will also call
+            // barrier.await() to signal the main thread to resume its work.
             for (int i = 0; i < NUM_GCS; i++) {
                 invokeGC();
-                checker.waitForCheckResult();
+                barrier.await();
             }
         } finally {
             // restore the default
@@ -166,6 +185,7 @@
 
     }
 
+
     private static void invokeGC() {
         System.out.println("Calling System.gc()");
         numGCs++;
@@ -180,8 +200,6 @@
     }
 
     static class Checker extends Thread {
-        private Object lock = new Object();
-        private Object go = new Object();
         private boolean checkerReady = false;
         private int waiters = 0;
         private boolean readyToCheck = false;
@@ -190,83 +208,48 @@
         };
         public void run() {
             while (true) {
-                synchronized (lock) {
-                    checkerReady = true;
-                    try {
-                        lock.wait();
-                    } catch (InterruptedException e) {
-                        // ignore
-                    }
+                try {
+                    signals.acquire(EXPECTED_NUM_POOLS);
                     checkResult();
-                    checkerReady = false;
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                } catch (BrokenBarrierException e) {
+                    throw new RuntimeException(e);
                 }
             }
         }
-        private void checkResult() {
+        private void checkResult() throws InterruptedException, BrokenBarrierException {
             for (PoolRecord pr : result.values()) {
                 if (pr.getListenerInvokedCount() != numGCs) {
-                    throw new RuntimeException("Listeners invoked count = " +
+                    fail("Listeners invoked count = " +
                          pr.getListenerInvokedCount() + " expected to be " +
                          numGCs);
                 }
                 if (pr.getNotifCount() != numGCs) {
-                    throw new RuntimeException("Notif Count = " +
+                    fail("Notif Count = " +
                          pr.getNotifCount() + " expected to be " +
                          numGCs);
                 }
 
                 long count = pr.getPool().getCollectionUsageThresholdCount();
                 if (count != numGCs) {
-                    throw new RuntimeException("CollectionUsageThresholdCount = " +
+                    fail("CollectionUsageThresholdCount = " +
                          count + " expected to be " + numGCs);
                 }
                 if (!pr.getPool().isCollectionUsageThresholdExceeded()) {
-                    throw new RuntimeException("isCollectionUsageThresholdExceeded" +
+                    fail("isCollectionUsageThresholdExceeded" +
                          " expected to be true");
                 }
             }
-            synchronized (go) {
-                // wait until the main thread is waiting for notification
-                while (waiters == 0) {
-                    try {
-                        go.wait(50);
-                    } catch (InterruptedException e) {
-                        // ignore
-                    }
-                }
-
-                System.out.println(Thread.currentThread().getName() +
-                    " notifying main thread to continue - result checking finished");
-                go.notify();
-            }
-        }
-        public void goCheckResult() {
-            System.out.println(Thread.currentThread().getName() +
-                " notifying to check result");
-            synchronized (lock) {
-                while (!checkerReady) {
-                    try {
-                        lock.wait(50);
-                    } catch (InterruptedException e) {
-                        // ignore
-                    }
-                }
-                lock.notify();
-            }
+            // wait until the main thread is waiting for notification
+            barrier.await();
+            System.out.println("notifying main thread to continue - result checking finished");
         }
 
-        public void waitForCheckResult() {
-            System.out.println(Thread.currentThread().getName() +
-                " waiting for result checking finishes");
-            synchronized (go) {
-                waiters++;
-                try {
-                    go.wait();
-                } catch (InterruptedException e) {
-                    // ignore
-                }
-                waiters--;
-            }
+        private void fail(String msg) {
+            // reset the barrier to cause BrokenBarrierException to avoid hanging
+            barrier.reset();
+            throw new RuntimeException(msg);
         }
     }
 }
--- a/jdk/test/java/lang/management/MemoryMXBean/CollectionUsageThresholdConcMarkSweepGC.sh	Mon Oct 18 18:04:02 2010 +0100
+++ b/jdk/test/java/lang/management/MemoryMXBean/CollectionUsageThresholdConcMarkSweepGC.sh	Tue Oct 19 09:49:08 2010 -0700
@@ -27,6 +27,7 @@
 # @summary Test CollectionUsageThreshold with concurrent marksweep collector
 # @author  Mandy Chung
 #
+# @ignore  6982965
 # @run build CollectionUsageThreshold
 # @run shell/timeout=300 CollectionUsageThresholdConcMarkSweepGC.sh
 #