1 /*
  2  * Copyright (c) 2003, 2020, 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  * @test
 26  * @key stress
 27  *
 28  * @summary converted from VM testbase nsk/stress/strace/strace004.
 29  * VM testbase keywords: [stress, strace]
 30  * VM testbase readme:
 31  * DESCRIPTION
 32  *     The test checks up java.lang.Thread.getAllStackTraces() method for many
 33  *     threads, that recursively invoke a native method in running mode
 34  *     ("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  *     This test is almost the same as nsk.stress.strace.strace003 except for
 42  *     checking is performed for java.lang.Thread.getAllStackTraces() method.
 43  * COMMENTS
 44  * java.lang.Thread.getAllStackTraces() is too slow method. So it is not successed
 45  * to catch an alive thread during execution of this method for the first snapshot
 46  * and it is needed to check on a promoted build due to the below assertion.
 47  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 48  * waiting for all threads started ...
 49  * >>> snapshot 1
 50  * waiting for threads finished
 51  * # To suppress the following error report, specify this argument
 52  * # after -XX: or in .hotspotrc:  SuppressErrorAt=/jniHandles.hpp:157
 53  * #
 54  * # HotSpot Virtual Machine Error, assertion failure
 55  * # Please report this error at
 56  * # http://java.sun.com/cgi-bin/bugreport.cgi
 57  * #
 58  * # Java VM: Java HotSpot(TM) Client VM (1.4.1-internal-debug mixed mode)
 59  * #
 60  * # assert(result != ((oop)::badJNIHandleVal), "Pointing to zapped jni handle area")
 61  * #
 62  * # Error ID: src/share/vm/runtime/jniHandles.hpp, 157 [ Patched ]
 63  * #
 64  * # Problematic Thread: prio=5 tid=0x001976e0 nid=0x96 runnable
 65  * #
 66  * Heap at VM Abort:
 67  * Heap
 68  *  def new generation   total 2112K, used 455K [0xf1800000, 0xf1a20000, 0xf1f10000)
 69  *   eden space 2048K,  22% used [0xf1800000, 0xf1871f60, 0xf1a00000)
 70  *   from space 64K,   0% used [0xf1a00000, 0xf1a00000, 0xf1a10000)
 71  *   to   space 64K,   0% used [0xf1a10000, 0xf1a10000, 0xf1a20000)
 72  *  tenured generation   total 1408K, used 0K [0xf1f10000, 0xf2070000, 0xf5800000)
 73  *    the space 1408K,   0% used [0xf1f10000, 0xf1f10000, 0xf1f10200, 0xf2070000)
 74  *  compacting perm gen  total 4096K, used 1025K [0xf5800000, 0xf5c00000, 0xf9800000)
 75  *    the space 4096K,  25% used [0xf5800000, 0xf5900660, 0xf5900800, 0xf5c00000)
 76  * Dumping core....
 77  * Abort
 78  * Finished at: Fri Apr 25 18:01:37 NSK 2003
 79  *
 80  * @library /vmTestbase
 81  *          /test/lib
 82  * @run main/othervm/native nsk.stress.strace.strace004
 83  */
 84 
 85 package nsk.stress.strace;
 86 
 87 import nsk.share.ArgumentParser;
 88 import nsk.share.Log;
 89 
 90 import java.io.PrintStream;
 91 import java.util.Map;
 92 
 93 /**
 94  * The test check up <code>java.lang.Thread.getAllStackTraces()</code> method for many
 95  * threads, that recursively invoke a native method in running mode ("alive" stack).
 96  * <p>
 97  * <p>The test creates <code>THRD_COUNT</code> instances of <code>strace004Thread</code>
 98  * class, tries to get their stack traces and checks up that returned array contains
 99  * correct stack frames. Each stack frame must be corresponded to one of the following
100  * methods defined by the <code>EXPECTED_METHODS</code> array.</p>
101  * <p>These checking are performed <code>REPEAT_COUNT</code> times.</p>
102  */
103 public class strace004 {
104 
105     static final int DEPTH = 100;
106     static final int THRD_COUNT = 100;
107     static final int REPEAT_COUNT = 10;
108     static final String[] EXPECTED_METHODS = {
109             "java.lang.System.arraycopy",
110             "java.lang.Object.wait",
111             "java.lang.Thread.exit",
112             "java.lang.Thread.yield",
113             "java.lang.ThreadGroup.remove",
114             "java.lang.ThreadGroup.threadTerminated",
115             "nsk.stress.strace.strace004Thread.run",
116             "nsk.stress.strace.strace004Thread.recursiveMethod"
117     };
118 
119 
120     static volatile boolean isLocked = false;
121     static PrintStream out;
122     static long waitTime = 2;
123 
124     static Object waitStart = new Object();
125 
126     static strace004Thread[] threads;
127     static StackTraceElement[][] snapshots = new StackTraceElement[THRD_COUNT][];
128     static Log log;
129 
130     volatile int achivedCount = 0;
131 
132     public static void main(String[] args) {
133         out = System.out;
134         int exitCode = run(args);
135         System.exit(exitCode + 95);
136     }
137 
138     public static int run(String[] args) {
139         ArgumentParser argHandler = new ArgumentParser(args);
140         log = new Log(out, argHandler);
141         waitTime = argHandler.getWaitTime() * 60000;
142 
143         strace004 test = new strace004();
144         boolean res = true;
145 
146         for (int j = 0; j < REPEAT_COUNT; j++) {
147             test.startThreads();
148 
149             if (!test.makeSnapshot(j + 1)) res = false;
150 
151             display("waiting for threads finished\n");
152             test.finishThreads();
153         }
154 
155         if (!res) {
156             complain("***>>>Test failed<<<***");
157             return 2;
158         }
159 
160         return 0;
161     }
162 
163     void startThreads() {
164         threads = new strace004Thread[THRD_COUNT];
165         achivedCount = 0;
166 
167         String tmp_name;
168         for (int i = 0; i < THRD_COUNT; i++) {
169             tmp_name = "strace004Thread" + Integer.toString(i);
170             threads[i] = new strace004Thread(this, tmp_name);
171         }
172 
173         for (int i = 0; i < THRD_COUNT; i++) {
174             threads[i].start();
175         }
176 
177         waitFor("all threads started ...");
178         synchronized (waitStart) {
179             isLocked = true;
180             waitStart.notifyAll();
181         }
182         try {
183             Thread.yield();
184             Thread.sleep(1);
185         } catch (InterruptedException e) {
186             complain("" + e);
187         }
188     }
189 
190     void waitFor(String msg) {
191         if (msg.length() > 0)
192             display("waiting for " + msg);
193 
194         while (achivedCount < THRD_COUNT) {
195             try {
196                 Thread.sleep(1);
197             } catch (InterruptedException e) {
198                 complain("" + e);
199             }
200         }
201         achivedCount = 0;
202     }
203 
204     boolean makeSnapshot(int repeat_number) {
205 
206         Map traces = Thread.getAllStackTraces();
207         for (int i = 0; i < threads.length; i++) {
208             snapshots[i] = (StackTraceElement[]) traces.get(threads[i]);
209         }
210 
211         return checkTraces(repeat_number);
212     }
213 
214     boolean checkTraces(int repeat_number) {
215         StackTraceElement[] elements;
216 
217         boolean res = true;
218         display(">>> snapshot " + repeat_number);
219         int expectedCount = DEPTH + 1;
220 
221         for (int i = 0; i < threads.length; i++) {
222             elements = snapshots[i];
223 
224             if (elements == null)
225                 continue;
226 
227             if (elements.length == 0)
228                 continue;
229 
230             if (elements.length > 3) {
231                 display("\tchecking " + threads[i].getName()
232                         + "(trace elements: " + elements.length + ")");
233             }
234 
235             if (elements.length > expectedCount) {
236                 complain(threads[i].getName() + ">Contains more then " +
237                         +expectedCount + " elements");
238             }
239 
240             for (int j = 0; j < elements.length; j++) {
241                 if (!checkElement(elements[j])) {
242                     complain(threads[i].getName() + ">Unexpected method name: "
243                             + elements[j].getMethodName());
244                     complain("\tat " + j + " position");
245                     if (elements[j].isNativeMethod()) {
246                         complain("\tline number: (native method)");
247                         complain("\tclass name: " + elements[j].getClassName());
248                     } else {
249                         complain("\tline number: " + elements[j].getLineNumber());
250                         complain("\tclass name: " + elements[j].getClassName());
251                         complain("\tfile name: " + elements[j].getFileName());
252                     }
253                     res = false;
254                 }
255             }
256         }
257         return res;
258     }
259 
260     boolean checkElement(StackTraceElement element) {
261         String name = element.getClassName() + "." + element.getMethodName();
262         for (int i = 0; i < EXPECTED_METHODS.length; i++) {
263             if (EXPECTED_METHODS[i].compareTo(name) == 0)
264                 return true;
265         }
266         return false;
267     }
268 
269     void finishThreads() {
270         try {
271             for (int i = 0; i < threads.length; i++) {
272                 if (threads[i].isAlive())
273                     threads[i].join(waitTime / THRD_COUNT);
274             }
275         } catch (InterruptedException e) {
276             complain("" + e);
277         }
278         isLocked = false;
279     }
280 
281     static void display(String message) {
282         log.display(message);
283     }
284 
285     static void complain(String message) {
286         log.complain(message);
287     }
288 
289 }
290 
291 class strace004Thread extends Thread {
292 
293     private int currentDepth = 0;
294 
295     strace004 test;
296 
297     static {
298         try {
299             System.loadLibrary("strace004");
300         } catch (UnsatisfiedLinkError e) {
301             System.err.println("Could not load strace004 library");
302             System.err.println("java.library.path:"
303                     + System.getProperty("java.library.path"));
304             throw e;
305         }
306     }
307 
308     strace004Thread(strace004 test, String name) {
309         this.test = test;
310         setName(name);
311     }
312 
313     public void run() {
314 
315         recursiveMethod();
316 
317     }
318 
319     native void recursiveMethod();
320 }