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 }