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/strace005.
 29  * VM testbase keywords: [stress, strace]
 30  * VM testbase readme:
 31  * DESCRIPTION
 32  *     The test checks up java.lang.Thread.getStackTrace() method for many threads,
 33  *     that recursively invoke pure java and native methods by turns in running
 34  *     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 and
 42  *     nsk.stress.strace.strace003 except for the recursive methods are
 43  *     pure java and native one.
 44  * COMMENTS
 45  * Below assertion is revealed on engineer's build. It is needed to check
 46  * on a promoted build.
 47  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 48  * waiting for all threads started ...
 49  * Unexpected Signal : 11 occurred at PC=0xFDBB7820
 50  * Function=[Unknown. Nearest: SUNWprivate_1.1+0x3B7820]
 51  * Library=java/vitp/jdk/4593133/solaris-sparc/jre/lib/sparc/client/libjvm.so
 52  * Current Java thread:
 53  *         at nsk.stress.strace.strace005Thread.recursiveMethod2(Native Method)
 54  *         at nsk.stress.strace.strace005Thread.recursiveMethod1(strace005.java:285)
 55  *     . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 56  *         at nsk.stress.strace.strace005Thread.recursiveMethod2(Native Method)
 57  *         at nsk.stress.strace.strace005Thread.recursiveMethod1(strace005.java:285)
 58  *         at nsk.stress.strace.strace005Thread.recursiveMethod2(Native Method)
 59  * Dynamic libraries:
 60  * 0x10000         jdk/4593133/solaris-sparc/bin/java
 61  * 0xff350000      /usr/lib/libthread.so.1
 62  * 0xff390000      /usr/lib/libdl.so.1
 63  * 0xff200000      /usr/lib/libc.so.1
 64  * 0xff330000      /usr/platform/SUNW,Ultra-60/lib/libc_psr.so.1
 65  * 0xfd800000      java/vitp/jdk/4593133/solaris-sparc/jre/lib/sparc/client/libjvm.so
 66  * 0xff2d0000      /usr/lib/libCrun.so.1
 67  * 0xff1d0000      /usr/lib/libsocket.so.1
 68  * 0xff100000      /usr/lib/libnsl.so.1
 69  * 0xff0d0000      /usr/lib/libm.so.1
 70  * 0xff0b0000      /usr/lib/libsched.so.1
 71  * 0xff300000      /usr/lib/libw.so.1
 72  * 0xff090000      /usr/lib/libmp.so.2
 73  * 0xff050000      java/vitp/jdk/4593133/solaris-sparc/jre/lib/sparc/native_threads/libhpi.so
 74  * 0xfd7d0000      java/vitp/jdk/4593133/solaris-sparc/jre/lib/sparc/libverify.so
 75  * 0xfd790000      java/vitp/jdk/4593133/solaris-sparc/jre/lib/sparc/libjava.so
 76  * 0xfe7e0000      java/vitp/jdk/4593133/solaris-sparc/jre/lib/sparc/libzip.so
 77  * 0xfc6e0000      java/vitp/tests/4593133/src/libstrace005.so
 78  * Heap at VM Abort:
 79  * Heap
 80  *  def new generation   total 2112K, used 336K [0xf1800000, 0xf1a20000, 0xf1f10000)
 81  *   eden space 2048K,  16% used [0xf1800000, 0xf1854300, 0xf1a00000)
 82  *   from space 64K,   0% used [0xf1a00000, 0xf1a00000, 0xf1a10000)
 83  *   to   space 64K,   0% used [0xf1a10000, 0xf1a10000, 0xf1a20000)
 84  *  tenured generation   total 1408K, used 0K [0xf1f10000, 0xf2070000, 0xf5800000)
 85  *    the space 1408K,   0% used [0xf1f10000, 0xf1f10000, 0xf1f10200, 0xf2070000)
 86  *  compacting perm gen  total 4096K, used 1020K [0xf5800000, 0xf5c00000, 0xf9800000)
 87  *    the space 4096K,  24% used [0xf5800000, 0xf58ff028, 0xf58ff200, 0xf5c00000)
 88  * Local Time = Fri Apr 25 18:09:16 2003
 89  * Elapsed Time = 13
 90  * #
 91  * # HotSpot Virtual Machine Error : 11
 92  * # Error ID : src/share/vm/runtime/os.cpp, 753 [ Patched ]
 93  * # Please report this error at
 94  * # http://java.sun.com/cgi-bin/bugreport.cgi
 95  * #
 96  * # Java VM: Java HotSpot(TM) Client VM (1.4.1-internal-debug mixed mode)
 97  * #
 98  * # An error report file has been saved as hs_err_pid16847.log.
 99  * # Please refer to the file for further information.
100  * #
101  * Dumping core....
102  * Abort
103  * Finished at: Fri Apr 25 18:09:17 NSK 2003
104  *
105  * @library /vmTestbase
106  *          /test/lib
107  * @run main/othervm/native nsk.stress.strace.strace005
108  */
109 
110 package nsk.stress.strace;
111 
112 import nsk.share.ArgumentParser;
113 import nsk.share.Failure;
114 import nsk.share.Log;
115 
116 import java.io.PrintStream;
117 
118 /**
119  * The test checks up <code>java.lang.Thread.getStackTrace()</code> method for many threads,
120  * that recursively invoke pure java and native methods by turns in running mode
121  * ("alive" stack).
122  * <p>
123  * <p>The test creates <code>THRD_COUNT</code> instances of <code>strace005Thread</code>
124  * class, tries to get their stack traces and checks up that returned array contains
125  * correct stack frames. Each stack frame must be corresponded to one of the following
126  * methods defined by the <code>EXPECTED_METHODS</code> array.</p>
127  * <p>These checking are performed <code>REPEAT_COUNT</code> times.</p>
128  */
129 public class strace005 {
130 
131     static final int DEPTH = 500;
132     static final int THRD_COUNT = 100;
133     static final int REPEAT_COUNT = 10;
134     static final String[] EXPECTED_METHODS = {
135             "java.lang.System.arraycopy",
136             "java.lang.Object.wait",
137             "java.lang.Object.wait0",
138             "java.lang.System$2.headStackableScope",
139             "java.lang.Thread.headStackableScopes",
140             "java.lang.Thread.exit",
141             "java.lang.Thread.yield",
142             "java.lang.Thread.yield0",
143             "java.lang.Thread.clearReferences",
144             "java.lang.Thread.getVirtualThread",
145             "java.lang.Thread.currentCarrierThread",
146             "java.lang.Thread.currentThread",
147             "java.lang.Thread.currentThread0",
148             "java.lang.Thread.threadContainer",
149             "java.lang.ThreadGroup.remove",
150             "java.lang.ThreadGroup.threadTerminated",
151             "jdk.internal.vm.StackableScope.head",
152             "jdk.internal.vm.StackableScope.popAll",
153             "nsk.stress.strace.strace005Thread.run",
154             "nsk.stress.strace.strace005Thread.recursiveMethod1",
155             "nsk.stress.strace.strace005Thread.recursiveMethod2"
156     };
157 
158 
159     static volatile boolean isLocked = false;
160     static PrintStream out;
161     static long waitTime = 2;
162 
163     static Object waitStart = new Object();
164 
165     static strace005Thread[] threads;
166     static StackTraceElement[][] snapshots = new StackTraceElement[THRD_COUNT][];
167     static Log log;
168 
169     volatile int achivedCount = 0;
170 
171     public static void main(String[] args) {
172         out = System.out;
173         int exitCode = run(args);
174         System.exit(exitCode + 95);
175     }
176 
177     public static int run(String[] args) {
178         ArgumentParser argHandler = new ArgumentParser(args);
179         log = new Log(out, argHandler);
180         waitTime = argHandler.getWaitTime() * 60000;
181 
182         strace005 test = new strace005();
183         boolean res = true;
184 
185         for (int j = 0; j < REPEAT_COUNT; j++) {
186             test.startThreads();
187 
188             if (!test.makeSnapshot(j + 1)) res = false;
189 
190             display("waiting for threads finished\n");
191             test.finishThreads();
192         }
193 
194         if (!res) {
195             complain("***>>>Test failed<<<***");
196             return 2;
197         }
198 
199         return 0;
200     }
201 
202     void startThreads() {
203         threads = new strace005Thread[THRD_COUNT];
204         achivedCount = 0;
205 
206         String tmp_name;
207         for (int i = 0; i < THRD_COUNT; i++) {
208             tmp_name = "strace005Thread" + Integer.toString(i);
209             threads[i] = new strace005Thread(this, tmp_name);
210 //            threads[i].setPriority(Thread.MIN_PRIORITY);
211         }
212 
213         for (int i = 0; i < THRD_COUNT; i++) {
214             threads[i].start();
215         }
216 
217         waitFor("all threads started ...");
218         synchronized (waitStart) {
219             isLocked = true;
220             waitStart.notifyAll();
221         }
222         try {
223             Thread.yield();
224             Thread.sleep(1);
225         } catch (InterruptedException e) {
226             complain("" + e);
227         }
228     }
229 
230     void waitFor(String msg) {
231         if (msg.length() > 0)
232             display("waiting for " + msg);
233 
234         while (achivedCount < THRD_COUNT) {
235             try {
236                 Thread.sleep(1);
237             } catch (InterruptedException e) {
238                 complain("" + e);
239             }
240         }
241         achivedCount = 0;
242     }
243 
244     boolean makeSnapshot(int repeat_number) {
245         // wait for native resolution completed (all threads have finished recursiveMethod2)
246         boolean isNativeResolved = false;
247         while (!isNativeResolved) {
248             try {
249                 isNativeResolved = true;
250                 for (int i = 0; i < threads.length; ++i)
251                     if (!threads[i].isNativeResolved)
252                         isNativeResolved = false;
253                 Thread.sleep(20);
254             } catch (InterruptedException e) {
255                 throw new Error(e);
256             }
257         }
258 
259         for (int i = 0; i < threads.length; i++) {
260             snapshots[i] = threads[i].getStackTrace();
261         }
262 
263         return checkTraces(repeat_number);
264     }
265 
266     boolean checkTraces(int repeat_number) {
267         StackTraceElement[] elements;
268 
269         boolean res = true;
270         display(">>> snapshot " + repeat_number);
271         int expectedCount = DEPTH + 1;
272 
273         for (int i = 0; i < threads.length; i++) {
274             elements = snapshots[i];
275 
276             if (elements == null || elements.length == 0)
277                 continue;
278 
279             if (elements.length > 0) {
280                 display("\tchecking " + threads[i].getName()
281                         + "(trace elements: " + elements.length + ")");
282             }
283 
284             if (elements.length > expectedCount) {
285                 complain(threads[i].getName() + ">Contains more then " +
286                         +expectedCount + " elements");
287             }
288 
289             for (int j = 0; j < elements.length; j++) {
290                 if (!checkElement(elements[j])) {
291                     complain(threads[i].getName() + ">Unexpected method name: "
292                             + elements[j].getMethodName());
293                     complain("\tat " + j + " position");
294                     if (elements[j].isNativeMethod()) {
295                         complain("\tline number: (native method)");
296                         complain("\tclass name: " + elements[j].getClassName());
297                     } else {
298                         complain("\tline number: " + elements[j].getLineNumber());
299                         complain("\tclass name: " + elements[j].getClassName());
300                         complain("\tfile name: " + elements[j].getFileName());
301                     }
302                     res = false;
303                 }
304             }
305         }
306         return res;
307     }
308 
309     boolean checkElement(StackTraceElement element) {
310         String name = element.getClassName() + "." + element.getMethodName();
311         for (int i = 0; i < EXPECTED_METHODS.length; i++) {
312             if (name.startsWith(EXPECTED_METHODS[i]))
313                 return true;
314         }
315         return false;
316     }
317 
318     void finishThreads() {
319         try {
320             for (int i = 0; i < threads.length; i++) {
321                 if (threads[i].isAlive())
322                     threads[i].join(waitTime / THRD_COUNT);
323             }
324         } catch (InterruptedException e) {
325             complain("" + e);
326         }
327         isLocked = false;
328     }
329 
330     static void display(String message) {
331         log.display(message);
332     }
333 
334     static void complain(String message) {
335         log.complain(message);
336     }
337 
338 }
339 
340 /**
341  * The test creates many instances of <code>strace005Thread</code> class and tries
342  * to get their stack traces.
343  */
344 class strace005Thread extends Thread {
345 
346     private int currentDepth = 0;
347     public boolean isNativeResolved = false;
348 
349     strace005 test;
350 
351     static {
352         try {
353             System.loadLibrary("strace005");
354         } catch (UnsatisfiedLinkError e) {
355             System.err.println("Could not load strace005 library");
356             System.err.println("java.library.path:"
357                     + System.getProperty("java.library.path"));
358             throw e;
359         }
360     }
361 
362     strace005Thread(strace005 test, String name) {
363         this.test = test;
364         setName(name);
365     }
366 
367     public void run() {
368 
369         recursiveMethod1();
370 
371     }
372 
373     void recursiveMethod1() {
374 
375         currentDepth++;
376 
377         if (currentDepth == 1) {
378             synchronized (test) {
379                 test.achivedCount++;
380             }
381 
382             int alltime = 0;
383             while (!strace005.isLocked) {
384                 synchronized (test) {
385                     try {
386                         test.wait(1);
387                         alltime++;
388                     } catch (InterruptedException e) {
389                         strace005.complain("" + e);
390                     }
391                     if (alltime > strace005.waitTime) {
392                         throw new Failure("out of wait time");
393                     }
394                 }
395             }
396         } else if (currentDepth > 1 && !isNativeResolved)
397             isNativeResolved = true;
398 
399         if (strace005.DEPTH - currentDepth > 0) {
400             try {
401                 Thread.yield();
402                 recursiveMethod2();
403             } catch (StackOverflowError e) {
404                 // ignore this exception
405             }
406         }
407 
408         currentDepth--;
409     }
410 
411     native void recursiveMethod2();
412 }