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