1 /*
   2  * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 /*
  26  * @test
  27  * @key stress
  28  *
  29  * @summary converted from VM testbase nsk/stress/strace/strace002.
  30  * VM testbase keywords: [stress, quick, strace]
  31  * VM testbase readme:
  32  * DESCRIPTION
  33  *     The test checks up java.lang.Thread.getAllStackTraces() method for many
  34  *     threads, that recursively invoke a pure java method in running mode
  35  *     ("alive" stack).
  36  *     The test fails if:
  37  *     - amount of stack trace elements is more than depth of recursion plus
  38  *       four elements corresponding to invocations of Thread.run(), Thread.wait(),
  39  *       Thread.exit(), Thread.yield() and ThreadGroup.remove() methods;
  40  *     - there is at least one element corresponding to invocation of unexpected
  41  *       method.
  42  *     This test is almost the same as nsk.stress.strace.strace001 except for
  43  *     checking is performed for java.lang.Thread.getAllStackTraces() method.
  44  *
  45  * @library /vmTestbase
  46  *          /test/lib
  47  * @run driver jdk.test.lib.FileInstaller . .
  48  * @run main/othervm nsk.stress.strace.strace002
  49  */
  50 
  51 
  52 package nsk.stress.strace;
  53 
  54 import nsk.share.ArgumentParser;
  55 import nsk.share.Failure;
  56 import nsk.share.Log;
  57 
  58 import java.io.PrintStream;
  59 import java.util.Map;
  60 
  61 /**
  62  * The test check up <code>java.lang.Thread.getAllStackTraces()</code> method for many
  63  * threads, that recursively invoke a pure java method in running mode ("alive" stack).
  64  * <p>
  65  * <p>The test creates <code>THRD_COUNT</code> instances of <code>strace002Thread</code>
  66  * class, tries to get their stack traces and checks up that returned array contains
  67  * correct stack frames. Each stack frame must be corresponded to one of the following
  68  * methods defined by the <code>EXPECTED_METHODS</code> array.</p>
  69  * <p>These checking are performed <code>REPEAT_COUNT</code> times.</p>
  70  */
  71 public class strace002 {
  72 
  73     static final int DEPTH = 200;
  74     static final int THRD_COUNT = 100;
  75     static final int REPEAT_COUNT = 10;
  76     static final String[] EXPECTED_METHODS = {
  77             "java.lang.System.arraycopy",
  78             "java.lang.Object.wait",
  79             "java.lang.Thread.exit",
  80             "java.lang.Thread.yield",
  81             "java.lang.ThreadGroup.remove",
  82             "java.lang.ThreadGroup.threadTerminated",
  83             "nsk.stress.strace.strace002Thread.run",
  84             "nsk.stress.strace.strace002Thread.recursiveMethod"
  85     };
  86 
  87 
  88     static volatile boolean isLocked = false;
  89     static PrintStream out;
  90     static long waitTime = 2;
  91 
  92     static Object waitStart = new Object();
  93 
  94     static strace002Thread[] threads;
  95     static StackTraceElement[][] snapshots = new StackTraceElement[THRD_COUNT][];
  96     static Log log;
  97 
  98     public static void main(String[] args) {
  99         out = System.out;
 100         int exitCode = run(args);
 101         System.exit(exitCode + 95);
 102     }
 103 
 104     volatile int achivedCount = 0;
 105 
 106     public static int run(String[] args) {
 107 
 108         ArgumentParser argHandler = new ArgumentParser(args);
 109         log = new Log(out, argHandler);
 110         waitTime = argHandler.getWaitTime() * 60000;
 111 
 112         strace002 test = new strace002();
 113         boolean res = true;
 114 
 115         for (int j = 0; j < REPEAT_COUNT; j++) {
 116             test.startThreads();
 117 
 118             if (!test.makeSnapshot(j + 1)) res = false;
 119 
 120             display("waiting for threads finished\n");
 121             test.finishThreads();
 122         }
 123 
 124         if (!res) {
 125             complain("***>>>Test failed<<<***");
 126             return 2;
 127         }
 128 
 129         return 0;
 130     }
 131 
 132     void startThreads() {
 133         threads = new strace002Thread[THRD_COUNT];
 134         achivedCount = 0;
 135 
 136         String tmp_name;
 137         for (int i = 0; i < THRD_COUNT; i++) {
 138             tmp_name = "strace002Thread" + Integer.toString(i);
 139             threads[i] = new strace002Thread(this, tmp_name);
 140         }
 141 
 142         for (int i = 0; i < THRD_COUNT; i++) {
 143             threads[i].start();
 144         }
 145 
 146         waitFor("all threads started ...");
 147         synchronized (waitStart) {
 148             isLocked = true;
 149             waitStart.notifyAll();
 150         }
 151         try {
 152             Thread.yield();
 153             Thread.sleep(1);
 154         } catch (InterruptedException e) {
 155             complain("" + e);
 156         }
 157     }
 158 
 159     void waitFor(String msg) {
 160         if (msg.length() > 0)
 161             display("waiting for " + msg);
 162 
 163         while (achivedCount < THRD_COUNT) {
 164             try {
 165                 Thread.sleep(1);
 166             } catch (InterruptedException e) {
 167                 complain("" + e);
 168             }
 169         }
 170         achivedCount = 0;
 171     }
 172 
 173     boolean makeSnapshot(int repeat_number) {
 174 
 175         Map traces = Thread.getAllStackTraces();
 176         for (int i = 0; i < threads.length; i++) {
 177             snapshots[i] = (StackTraceElement[]) traces.get(threads[i]);
 178         }
 179 
 180         return checkTraces(repeat_number);
 181     }
 182 
 183     boolean checkTraces(int repeat_number) {
 184         StackTraceElement[] elements;
 185 
 186         boolean res = true;
 187         display(">>> snapshot " + repeat_number);
 188         int expectedCount = DEPTH + 1;
 189 
 190         for (int i = 0; i < threads.length; i++) {
 191             elements = snapshots[i];
 192 
 193             if (elements == null)
 194                 continue;
 195 
 196             if (elements.length == 0)
 197                 continue;
 198 
 199             if (elements.length > 3) {
 200                 display("\tchecking " + threads[i].getName()
 201                         + "(trace elements: " + elements.length + ")");
 202             }
 203 
 204             if (elements.length > expectedCount) {
 205                 complain(threads[i].getName() + ">Contains more then " +
 206                         +expectedCount + " elements");
 207             }
 208 
 209             for (int j = 0; j < elements.length; j++) {
 210                 if (!checkElement(elements[j])) {
 211                     complain(threads[i].getName() + ">Unexpected method name: "
 212                             + elements[j].getMethodName());
 213                     complain("\tat " + j + " position");
 214                     if (elements[j].isNativeMethod()) {
 215                         complain("\tline number: (native method)");
 216                         complain("\tclass name: " + elements[j].getClassName());
 217                     } else {
 218                         complain("\tline number: " + elements[j].getLineNumber());
 219                         complain("\tclass name: " + elements[j].getClassName());
 220                         complain("\tfile name: " + elements[j].getFileName());
 221                     }
 222                     res = false;
 223                 }
 224             }
 225         }
 226         return res;
 227     }
 228 
 229     boolean checkElement(StackTraceElement element) {
 230         String name = element.getClassName() + "." + element.getMethodName();
 231         for (int i = 0; i < EXPECTED_METHODS.length; i++) {
 232             if (EXPECTED_METHODS[i].compareTo(name) == 0)
 233                 return true;
 234         }
 235         return false;
 236     }
 237 
 238     void finishThreads() {
 239         try {
 240             for (int i = 0; i < threads.length; i++) {
 241                 if (threads[i].isAlive())
 242                     threads[i].join(waitTime / THRD_COUNT);
 243             }
 244         } catch (InterruptedException e) {
 245             complain("" + e);
 246         }
 247         isLocked = false;
 248     }
 249 
 250     static void display(String message) {
 251         log.display(message);
 252     }
 253 
 254     static void complain(String message) {
 255         log.complain(message);
 256     }
 257 
 258 
 259 }
 260 
 261 class strace002Thread extends Thread {
 262 
 263     private int currentDepth = 0;
 264 
 265     strace002 test;
 266 
 267     strace002Thread(strace002 test, String name) {
 268         this.test = test;
 269         setName(name);
 270     }
 271 
 272     public void run() {
 273         try {
 274             recursiveMethod();
 275         } catch (Throwable throwable) {
 276             System.err.println("# ERROR: " + getName() + ": " + throwable);
 277             System.exit(1);
 278         }
 279     }
 280 
 281     void recursiveMethod() {
 282 
 283         currentDepth++;
 284 
 285         if (currentDepth == 1) {
 286             synchronized (test) {
 287                 test.achivedCount++;
 288             }
 289 
 290             int alltime = 0;
 291             while (!test.isLocked) {
 292                 synchronized (test) {
 293                     try {
 294                         test.wait(1);
 295                         alltime++;
 296                     } catch (InterruptedException e) {
 297                         strace002.complain("" + e);
 298                     }
 299                     if (alltime > strace002.waitTime) {
 300                         throw new Failure("out of wait time");
 301                     }
 302                 }
 303             }
 304         }
 305 
 306         if (strace002.DEPTH - currentDepth > 0) {
 307             Thread.yield();
 308             recursiveMethod();
 309         }
 310 
 311         currentDepth--;
 312     }
 313 }