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.Object.wait0",
112             "java.lang.System$2.headStackableScope",
113             "java.lang.Thread.headStackableScopes",
114             "java.lang.Thread.exit",
115             "java.lang.Thread.yield",
116             "java.lang.Thread.yield0",
117             "java.lang.Thread.clearReferences",
118             "java.lang.Thread.currentCarrierThread",
119             "java.lang.Thread.currentThread",
120             "java.lang.Thread.currentThread0",
121             "java.lang.Thread.getVirtualThread",
122             "java.lang.Thread.threadContainer",
123             "java.lang.ThreadGroup.remove",
124             "java.lang.ThreadGroup.threadTerminated",
125             "jdk.internal.vm.StackableScope.head",
126             "jdk.internal.vm.StackableScope.popAll",
127             "nsk.stress.strace.strace004Thread.run",
128             "nsk.stress.strace.strace004Thread.recursiveMethod"
129     };
130 
131 
132     static volatile boolean isLocked = false;
133     static PrintStream out;
134     static long waitTime = 2;
135 
136     static Object waitStart = new Object();
137 
138     static strace004Thread[] threads;
139     static StackTraceElement[][] snapshots = new StackTraceElement[THRD_COUNT][];
140     static Log log;
141 
142     volatile int achivedCount = 0;
143 
144     public static void main(String[] args) {
145         out = System.out;
146         int exitCode = run(args);
147         System.exit(exitCode + 95);
148     }
149 
150     public static int run(String[] args) {
151         ArgumentParser argHandler = new ArgumentParser(args);
152         log = new Log(out, argHandler);
153         waitTime = argHandler.getWaitTime() * 60000;
154 
155         strace004 test = new strace004();
156         boolean res = true;
157 
158         for (int j = 0; j < REPEAT_COUNT; j++) {
159             test.startThreads();
160 
161             if (!test.makeSnapshot(j + 1)) res = false;
162 
163             display("waiting for threads finished\n");
164             test.finishThreads();
165         }
166 
167         if (!res) {
168             complain("***>>>Test failed<<<***");
169             return 2;
170         }
171 
172         return 0;
173     }
174 
175     void startThreads() {
176         threads = new strace004Thread[THRD_COUNT];
177         achivedCount = 0;
178 
179         String tmp_name;
180         for (int i = 0; i < THRD_COUNT; i++) {
181             tmp_name = "strace004Thread" + Integer.toString(i);
182             threads[i] = new strace004Thread(this, tmp_name);
183         }
184 
185         for (int i = 0; i < THRD_COUNT; i++) {
186             threads[i].start();
187         }
188 
189         waitFor("all threads started ...");
190         synchronized (waitStart) {
191             isLocked = true;
192             waitStart.notifyAll();
193         }
194         try {
195             Thread.yield();
196             Thread.sleep(1);
197         } catch (InterruptedException e) {
198             complain("" + e);
199         }
200     }
201 
202     void waitFor(String msg) {
203         if (msg.length() > 0)
204             display("waiting for " + msg);
205 
206         while (achivedCount < THRD_COUNT) {
207             try {
208                 Thread.sleep(1);
209             } catch (InterruptedException e) {
210                 complain("" + e);
211             }
212         }
213         achivedCount = 0;
214     }
215 
216     boolean makeSnapshot(int repeat_number) {
217 
218         Map traces = Thread.getAllStackTraces();
219         for (int i = 0; i < threads.length; i++) {
220             snapshots[i] = (StackTraceElement[]) traces.get(threads[i]);
221         }
222 
223         return checkTraces(repeat_number);
224     }
225 
226     boolean checkTraces(int repeat_number) {
227         StackTraceElement[] elements;
228 
229         boolean res = true;
230         display(">>> snapshot " + repeat_number);
231         int expectedCount = DEPTH + 1;
232 
233         for (int i = 0; i < threads.length; i++) {
234             elements = snapshots[i];
235 
236             if (elements == null)
237                 continue;
238 
239             if (elements.length == 0)
240                 continue;
241 
242             if (elements.length > 3) {
243                 display("\tchecking " + threads[i].getName()
244                         + "(trace elements: " + elements.length + ")");
245             }
246 
247             if (elements.length > expectedCount) {
248                 complain(threads[i].getName() + ">Contains more then " +
249                         +expectedCount + " elements");
250             }
251 
252             for (int j = 0; j < elements.length; j++) {
253                 if (!checkElement(elements[j])) {
254                     complain(threads[i].getName() + ">Unexpected method name: "
255                             + elements[j].getMethodName());
256                     complain("\tat " + j + " position");
257                     if (elements[j].isNativeMethod()) {
258                         complain("\tline number: (native method)");
259                         complain("\tclass name: " + elements[j].getClassName());
260                     } else {
261                         complain("\tline number: " + elements[j].getLineNumber());
262                         complain("\tclass name: " + elements[j].getClassName());
263                         complain("\tfile name: " + elements[j].getFileName());
264                     }
265                     res = false;
266                 }
267             }
268         }
269         return res;
270     }
271 
272     boolean checkElement(StackTraceElement element) {
273         String name = element.getClassName() + "." + element.getMethodName();
274         for (int i = 0; i < EXPECTED_METHODS.length; i++) {
275             if (name.startsWith(EXPECTED_METHODS[i]))
276                 return true;
277         }
278         return false;
279     }
280 
281     void finishThreads() {
282         try {
283             for (int i = 0; i < threads.length; i++) {
284                 if (threads[i].isAlive())
285                     threads[i].join(waitTime / THRD_COUNT);
286             }
287         } catch (InterruptedException e) {
288             complain("" + e);
289         }
290         isLocked = false;
291     }
292 
293     static void display(String message) {
294         log.display(message);
295     }
296 
297     static void complain(String message) {
298         log.complain(message);
299     }
300 
301 }
302 
303 class strace004Thread extends Thread {
304 
305     private int currentDepth = 0;
306 
307     strace004 test;
308 
309     static {
310         try {
311             System.loadLibrary("strace004");
312         } catch (UnsatisfiedLinkError e) {
313             System.err.println("Could not load strace004 library");
314             System.err.println("java.library.path:"
315                     + System.getProperty("java.library.path"));
316             throw e;
317         }
318     }
319 
320     strace004Thread(strace004 test, String name) {
321         this.test = test;
322         setName(name);
323     }
324 
325     public void run() {
326 
327         recursiveMethod();
328 
329     }
330 
331     native void recursiveMethod();
332 }