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/strace001.
  30  * VM testbase keywords: [stress, quick, strace]
  31  * VM testbase readme:
  32  * DESCRIPTION
  33  *     The test checks up java.lang.Thread.getStackTrace() method for many threads,
  34  *     that recursively invoke a pure java method in running mode ("alive" stack).
  35  *     The test fails if:
  36  *     - amount of stack trace elements is more than depth of recursion plus
  37  *       four elements corresponding to invocations of Thread.run(), Thread.wait(),
  38  *       Thread.exit(), Thread.yield() and ThreadGroup.remove() methods;
  39  *     - there is at least one element corresponding to invocation of unexpected
  40  *       method.
  41  *
  42  * @library /vmTestbase
  43  *          /test/lib
  44  * @run driver jdk.test.lib.FileInstaller . .
  45  * @run main/othervm nsk.stress.strace.strace001
  46  */
  47 package nsk.stress.strace;
  48 
  49 import nsk.share.ArgumentParser;
  50 import nsk.share.Failure;
  51 import nsk.share.Log;
  52 
  53 import java.io.PrintStream;
  54 
  55 /**
  56  * The test check up <code>java.lang.Thread.getStackTrace()</code> method for many threads,
  57  * that recursively invoke a pure java method in running mode ("alive" stack).
  58  * <p>
  59  * <p>The test creates <code>THRD_COUNT</code> instances of <code>strace001Thread</code>
  60  * class, tries to get their stack traces and checks up that returned array contains
  61  * correct stack frames. Each stack frame must be corresponded to one of the following
  62  * methods defined by the <code>EXPECTED_METHODS</code> array.</p>
  63  * <p>These checking are performed <code>REPEAT_COUNT</code> times.</p>
  64  */
  65 public class strace001 {
  66 
  67     static final int DEPTH = 200;
  68     static final int THRD_COUNT = 100;
  69     static final int REPEAT_COUNT = 10;
  70     static final String[] EXPECTED_METHODS = {
  71             "java.lang.System.arraycopy",
  72             "java.lang.Object.wait",
  73             "java.lang.Thread.exit",
  74             "java.lang.Thread.yield",
  75             "java.lang.ThreadGroup.remove",
  76             "java.lang.ThreadGroup.threadTerminated",
  77             "nsk.stress.strace.strace001Thread.run",
  78             "nsk.stress.strace.strace001Thread.recursiveMethod"
  79     };
  80 
  81 
  82     static volatile boolean isLocked = false;
  83     static PrintStream out;
  84     static long waitTime = 2;
  85 
  86     static Object waitStart = new Object();
  87 
  88     static strace001Thread[] threads;
  89     static StackTraceElement[][] snapshots = new StackTraceElement[THRD_COUNT][];
  90     static Log log;
  91 
  92     public static void main(String[] args) {
  93         out = System.out;
  94         int exitCode = run(args);
  95         System.exit(exitCode + 95);
  96     }
  97 
  98     volatile int achivedCount = 0;
  99 
 100     public static int run(String[] args) {
 101 
 102         ArgumentParser argHandler = new ArgumentParser(args);
 103         log = new Log(out, argHandler);
 104         waitTime = argHandler.getWaitTime() * 60000;
 105 
 106         strace001 test = new strace001();
 107         boolean res = true;
 108 
 109         for (int j = 0; j < REPEAT_COUNT; j++) {
 110             test.startThreads();
 111 
 112             if (!test.makeSnapshot(j + 1)) res = false;
 113 
 114             display("waiting for threads finished\n");
 115             test.finishThreads();
 116         }
 117 
 118         if (!res) {
 119             complain("***>>>Test failed<<<***");
 120             return 2;
 121         }
 122 
 123         return 0;
 124     }
 125 
 126     void startThreads() {
 127         threads = new strace001Thread[THRD_COUNT];
 128         achivedCount = 0;
 129 
 130         String tmp_name;
 131         for (int i = 0; i < THRD_COUNT; i++) {
 132             tmp_name = "strace001Thread" + Integer.toString(i);
 133             threads[i] = new strace001Thread(this, tmp_name);
 134         }
 135 
 136         for (int i = 0; i < THRD_COUNT; i++) {
 137             threads[i].start();
 138         }
 139 
 140         waitFor("all threads started ...");
 141         synchronized (waitStart) {
 142             isLocked = true;
 143             waitStart.notifyAll();
 144         }
 145         try {
 146             Thread.yield();
 147             Thread.sleep(1);
 148         } catch (InterruptedException e) {
 149             complain("" + e);
 150         }
 151     }
 152 
 153     void waitFor(String msg) {
 154         if (msg.length() > 0)
 155             display("waiting for " + msg);
 156 
 157         while (achivedCount < THRD_COUNT) {
 158             try {
 159                 Thread.sleep(1);
 160             } catch (InterruptedException e) {
 161                 complain("" + e);
 162             }
 163         }
 164         achivedCount = 0;
 165     }
 166 
 167     boolean makeSnapshot(int repeat_number) {
 168 
 169         for (int i = 0; i < threads.length; i++) {
 170             snapshots[i] = threads[i].getStackTrace();
 171         }
 172 
 173         return checkTraces(repeat_number);
 174     }
 175 
 176     boolean checkTraces(int repeat_number) {
 177         StackTraceElement[] elements;
 178 
 179         boolean res = true;
 180         display(">>> snapshot " + repeat_number);
 181         int expectedCount = DEPTH + 1;
 182 
 183         for (int i = 0; i < threads.length; i++) {
 184             elements = snapshots[i];
 185 
 186             if (elements == null)
 187                 continue;
 188 
 189             if (elements.length == 0)
 190                 continue;
 191 
 192             if (elements.length > 3) {
 193                 display("\tchecking " + threads[i].getName()
 194                         + "(trace elements: " + elements.length + ")");
 195             }
 196 
 197             if (elements.length > expectedCount) {
 198                 complain(threads[i].getName() + ">Contains more then " +
 199                         +expectedCount + " elements");
 200             }
 201 
 202             for (int j = 0; j < elements.length; j++) {
 203                 if (!checkElement(elements[j])) {
 204                     complain(threads[i].getName() + ">Unexpected method name: "
 205                             + elements[j].getMethodName());
 206                     complain("\tat " + j + " position");
 207                     if (elements[j].isNativeMethod()) {
 208                         complain("\tline number: (native method)");
 209                         complain("\tclass name: " + elements[j].getClassName());
 210                     } else {
 211                         complain("\tline number: " + elements[j].getLineNumber());
 212                         complain("\tclass name: " + elements[j].getClassName());
 213                         complain("\tfile name: " + elements[j].getFileName());
 214                     }
 215                     res = false;
 216                 }
 217             }
 218         }
 219         return res;
 220     }
 221 
 222     boolean checkElement(StackTraceElement element) {
 223         String name = element.getClassName() + "." + element.getMethodName();
 224         for (int i = 0; i < EXPECTED_METHODS.length; i++) {
 225             if (EXPECTED_METHODS[i].compareTo(name) == 0)
 226                 return true;
 227         }
 228         return false;
 229     }
 230 
 231     void finishThreads() {
 232         try {
 233             for (int i = 0; i < threads.length; i++) {
 234                 if (threads[i].isAlive())
 235                     threads[i].join(waitTime / THRD_COUNT);
 236             }
 237         } catch (InterruptedException e) {
 238             complain("" + e);
 239         }
 240         isLocked = false;
 241     }
 242 
 243     static void display(String message) {
 244         log.display(message);
 245     }
 246 
 247     static void complain(String message) {
 248         log.complain(message);
 249     }
 250 }
 251 
 252 class strace001Thread extends Thread {
 253 
 254     private int currentDepth = 0;
 255 
 256     strace001 test;
 257 
 258     strace001Thread(strace001 test, String name) {
 259         this.test = test;
 260         setName(name);
 261     }
 262 
 263     public void run() {
 264         try {
 265             recursiveMethod();
 266         } catch (Throwable throwable) {
 267             System.err.println("# ERROR: " + getName() + ": " + throwable);
 268             System.exit(1);
 269         }
 270     }
 271 
 272     void recursiveMethod() {
 273 
 274         currentDepth++;
 275 
 276         if (currentDepth == 1) {
 277             synchronized (test) {
 278                 test.achivedCount++;
 279             }
 280 
 281             int alltime = 0;
 282             while (!strace001.isLocked) {
 283                 synchronized (test) {
 284                     try {
 285                         test.wait(1);
 286                         alltime++;
 287                     } catch (InterruptedException e) {
 288                         strace001.complain("" + e);
 289                     }
 290                     if (alltime > strace001.waitTime) {
 291                         throw new Failure("out of wait time");
 292                     }
 293                 }
 294             }
 295         }
 296 
 297         if (strace001.DEPTH - currentDepth > 0) {
 298             Thread.yield();
 299             recursiveMethod();
 300         }
 301 
 302         currentDepth--;
 303     }
 304 }