8035173: [TESTBUG] runtime/threads/CancellableThreadTest fails with OOM on windows-i586
authorctornqvi
Tue, 15 Apr 2014 19:03:51 +0200
changeset 24000 4ed166e87a9d
parent 23999 22eb7be3d99d
child 24023 965f85aeb674
child 24084 af1a193eb7b2
8035173: [TESTBUG] runtime/threads/CancellableThreadTest fails with OOM on windows-i586 Summary: Test ported to jtreg, thread pairs decreased from 1024 to 128 to avoid OOM on 32 bit Windows Reviewed-by: sla, dsimms
hotspot/test/runtime/Thread/CancellableThreadTest.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/Thread/CancellableThreadTest.java	Tue Apr 15 19:03:51 2014 +0200
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This test is useful for finding out whether a Thread can have a
+ * private variable indicate whether or not it is finished, and to illustrate
+ * the ease with which Threads terminate each other.
+ *
+ * @test
+ */
+
+public class CancellableThreadTest {
+    public static final int THREADPAIRS = Integer.parseInt(System.getProperty("test.threadpairs", "128"));
+
+    public static void main(String args[]) {
+        Thread[] threads = new Thread[THREADPAIRS];
+        Canceller[] cancellers = new Canceller[THREADPAIRS];
+
+        System.out.println("Running with " + THREADPAIRS + " thread pairs");
+
+        for (int i = 0; i < THREADPAIRS; i++) {
+            cancellers[i] = new Canceller(i);
+            threads[i] = new Thread(cancellers[i]);
+            threads[i].start();
+        }
+
+        for (int i = 0; i < THREADPAIRS; i++) {
+            try {
+                threads[i].join();
+            } catch (InterruptedException e) {
+            }
+
+            if (cancellers[i].failed) {
+                throw new RuntimeException(" Test failed in " + i + " th pair. See error messages above.");
+            }
+        }
+    }
+}
+
+class Canceller implements Runnable {
+
+    private final CancellableTimer timer;
+
+    public final String name;
+    public volatile boolean failed = false;
+    private volatile boolean hasBeenNotified = false;
+
+    public Canceller(int index) {
+        this.name = "Canceller #" + index;
+        timer = new CancellableTimer(index, this);
+    }
+
+    public void setHasBeenNotified() {
+        hasBeenNotified = true;
+    }
+
+    /**
+     * This method contains the "action" of this Canceller Thread.
+     * It starts a CancellableTimer, waits, and then interrupts the
+     * CancellableTimer after the CancellableTimer notifies it.  It then
+     * tries to join the CancellableTimer to itself and reports on whether
+     * it was successful in doing so.
+     */
+    public void run() {
+        Thread timerThread = new Thread(timer);
+
+        try {
+            synchronized(this) {
+                timerThread.start();
+                wait();
+            }
+        } catch (InterruptedException e) {
+            System.err.println(name + " was interrupted during wait()");
+            failed = true;
+        }
+
+        if (!hasBeenNotified) {
+            System.err.println(name + ".hasBeenNotified is not true as expected");
+            failed = true;
+        }
+
+        synchronized (timer) {
+            timerThread.interrupt();
+        }
+
+        try {
+            timerThread.join();
+        } catch (InterruptedException ie) {
+            System.err.println(name + " was interrupted while joining " +
+                    timer.name);
+            failed = true;
+        }
+
+        if (timerThread.isAlive()) {
+            System.err.println(timer.name + " is still alive after " + name +
+                    " attempted to join it.");
+            failed = true;
+        }
+    }
+}
+
+/**
+ * This non-public class is the Thread which the Canceller Thread deliberately
+ * interrupts and then joins to itself after this Thread has slept for a few milliseconds.
+ */
+
+class CancellableTimer implements Runnable {
+
+    public final String name;
+    private final Canceller myCanceller;
+
+    public CancellableTimer(int index, Canceller aCanceller) {
+        this.name = "CancellableTimer #" + index;
+        this.myCanceller = aCanceller;
+    }
+
+    /**
+     * This is where this CancellableTimer does its work. It notifies its
+     * Canceller, waits for the Canceller to interrupt it, then catches the
+     * InterruptedException, and sleeps for a few milliseconds before exiting.
+     */
+    public void run() {
+        try {
+            synchronized (this) {
+                synchronized (myCanceller) {
+                    myCanceller.setHasBeenNotified();
+                    myCanceller.notify();
+                }
+                wait();
+            }
+        } catch (InterruptedException first) {
+            // isInterrupted should've been cleared here and we should not register a
+            // second interrupt
+            if (Thread.currentThread().isInterrupted()) {
+                System.err.println(name + " should not register an interrupt here");
+                myCanceller.failed = true;
+            }
+
+            try {
+                Thread.sleep(1);
+            } catch (InterruptedException e) {
+                System.err.println(name + " was interrupted when sleeping");
+                myCanceller.failed = true;
+            }
+        }
+    }
+}