1 /*
2  * Copyright (c) 2007, 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  * jnistress006 is a class that sets up classes that do the work
26  * for the test.
27  *
28  * The Interrupter objects send interrupts to the JNIters.
29  * The GarbageGenerator objects generate garbage.
30  *
31  * sync[0] synchronizes the test cycles.
32  * sync[1] synchronizes access to exception counters.
33  * sync[2] synchronizes the cycle count update.  It also insures that
34  *         the interrupts do not interfere with the cycle count updates.
35  *         This is because cycle count updates are used to define cycles.
36  */
37 
38 
39 /*
40  * @test
41  * @key stress
42  *
43  * @summary converted from VM testbase nsk/stress/jni/jnistress006.
44  * VM testbase keywords: [stress, quick, feature_283, nonconcurrent]
45  *
46  * @library /vmTestbase
47  *          /test/lib
48  * @run main/othervm/native
49  *      nsk.stress.jni.jnistress006
50  *      -numTHREADer 20
51  *      -threadInterval 200
52  *      -numInterrupter 2
53  *      -interruptInterval 500
54  *      -numGarbage 80
55  *      -garbageInterval 5
56  *      -numIteration 260
57  */
58 
59 package nsk.stress.jni;
60 
61 import nsk.share.Consts;
62 import nsk.share.Debug;
63 import nsk.share.test.StressOptions;
64 
65 public class jnistress006 extends Thread {
66 
67     /* Maximum number of iterations.  Ignored if <= 0L */
68     static long numIteration = 0L;
69     /* Timeout */
70     static long timeOut;
71     /* Number of test class objects */
72     static int numJNIter = 1;
73     /* Time between JNI stressing by the threads under test */
74     /* (in milliseconds) */
75     static int jniInterval = 10000;
76     /* Number of interrupting threads */
77     static int numInterrupter = 1;
78     /* Time between interrupts in milliseconds */
79     static int interruptInterval = 100;
80     /* Number of garbage generating threads */
81     static int numGarbage = 1;
82     /* Time between garbage allocations in milliseconds */
83     static int garbageInterval = 100;
84     // The MAX quantity of creates global refs
85     static int jniStringAllocSize = 30000;
86 
87     private static StressOptions stressOptions;
88 
main(String[] argv)89     public static void main(String[] argv) {
90         try {
91             int i = 0;
92             int nJNISync = 10;
93             jnistress006 dm = null;
94             boolean errArg = false;
95 
96             stressOptions = new StressOptions(argv);
97 
98                         /* Process arguments */
99             while (!errArg && i < argv.length) {
100                             /* Number of iterations. Ignored if <= 0. */
101                 if (i < argv.length && argv[i].equals("-numIteration")) {
102                     ++i;
103                     if (i < argv.length && Character.isDigit(argv[i].charAt(0))) {
104                         try {
105                             numIteration = Long.parseLong(argv[i++]);
106                         } catch (NumberFormatException e) {
107                             errArg = true;
108                         }
109                     }
110                 } else if (i < argv.length && argv[i].equals("-numTHREADer")) {
111                     ++i;
112                     if (i < argv.length && Character.isDigit(argv[i].charAt(0))) {
113                         try {
114                             numJNIter = Integer.parseInt(argv[i++]);
115                         } catch (NumberFormatException e) {
116                             errArg = true;
117                         }
118                         if (numJNIter <= 0) errArg = true;
119                     }
120                 } else if (i < argv.length && argv[i].equals("-threadInterval")) {
121                     ++i;
122                     if (i < argv.length && Character.isDigit(argv[i].charAt(0))) {
123                         try {
124                             jniInterval = Integer.parseInt(argv[i++]);
125                         } catch (NumberFormatException e) {
126                             errArg = true;
127                         }
128                     }
129                 } else if (i < argv.length && argv[i].equals("-numInterrupter")) {
130                     ++i;
131                     if (i < argv.length && Character.isDigit(argv[i].charAt(0))) {
132                         try {
133                             numInterrupter = Integer.parseInt(argv[i++]);
134                         } catch (NumberFormatException e) {
135                             errArg = true;
136                         }
137                     }
138                 } else if (i < argv.length && argv[i].equals("-interruptInterval")) {
139                     ++i;
140                     if (i < argv.length && Character.isDigit(argv[i].charAt(0))) {
141                         try {
142                             interruptInterval = Integer.parseInt(argv[i++]);
143                         } catch (NumberFormatException e) {
144                             errArg = true;
145                         }
146                     }
147                 } else if (i < argv.length && argv[i].equals("-numGarbage")) {
148                     ++i;
149                     if (i < argv.length && Character.isDigit(argv[i].charAt(0))) {
150                         try {
151                             numGarbage = Integer.parseInt(argv[i++]);
152                         } catch (NumberFormatException e) {
153                             errArg = true;
154                         }
155                     }
156                 } else if (i < argv.length && argv[i].equals("-garbageInterval")) {
157                     ++i;
158                     if (i < argv.length && Character.isDigit(argv[i].charAt(0))) {
159                         try {
160                             garbageInterval = Integer.parseInt(argv[i++]);
161                         } catch (NumberFormatException e) {
162                             errArg = true;
163                         }
164                     }
165                 } else if (i < argv.length && argv[i].equals("-jniStringAllocSize")) {
166                     ++i;
167                     if (i < argv.length && Character.isDigit(argv[i].charAt(0))) {
168                         try {
169                             jniStringAllocSize = Integer.parseInt(argv[i++]);
170                         } catch (NumberFormatException e) {
171                             errArg = true;
172                         }
173                     }
174                 } else if (i < argv.length && argv[i].startsWith("-stress")) {
175                     ++i;
176                     if (i < argv.length && Character.isDigit(argv[i].charAt(0))) {
177                         ++i;
178                     }
179                 } else System.out.println("Argument #" + i++ + " is incorrect");
180             }
181 
182             numIteration *= stressOptions.getIterationsFactor();
183             numJNIter *= stressOptions.getThreadsFactor();
184             numInterrupter *= stressOptions.getThreadsFactor();
185             numGarbage *= stressOptions.getThreadsFactor();
186             timeOut = stressOptions.getTime() * 1000;
187 
188             sync = new Synchronizer[10];
189             for (i = 0; i < nJNISync; i++)
190                 sync[i] = new Synchronizer();
191             dm = new jnistress006(numIteration, numJNIter, jniInterval,
192                     numInterrupter, interruptInterval, numGarbage, garbageInterval);
193 
194             dm.start();
195 
196             try {
197                 dm.join(timeOut);
198             } catch (InterruptedException e) {
199                 System.out.println("TESTER THREAD WAS INTERRUPTED");
200                 System.exit(Consts.TEST_FAILED);
201             }
202 
203             if (DEBUG) System.out.println("jnistress006::main(): halt!");
204 
205             if (dm.isAlive()) {
206                 System.out.println("TIME LIMIT EXCEEDED");
207                 dm.halt();
208                 if (DEBUG) System.out.println("jnistress006::main(): join!");
209                 try {
210                     dm.join(10000L);
211                 } catch (InterruptedException e) {
212                     System.out.println("TESTER THREAD WAS INTERRUPTED");
213                     System.exit(Consts.TEST_FAILED);
214                 }
215             } else {
216                 System.out.println("TESTER THREAD FINISHED");
217             }
218 
219             if (DEBUG) System.out.println("jnistress006::main(): zzzz...");
220 
221             if (!JNIter006.passed())
222                 System.exit(Consts.TEST_FAILED);
223 
224         } catch (Throwable e) {
225             Debug.Fail(e);
226         }
227     }
228 
jnistress006( long iters, int nJNI, int jniInterval, int nInter, int iruptInterval, int nGarb, int garbInterval )229     jnistress006(
230             long iters,
231             int nJNI,
232             int jniInterval,
233             int nInter,
234             int iruptInterval,
235             int nGarb,
236             int garbInterval
237     ) {
238         int i = 0;
239         nCycles = iters;
240         /* Should have at least one of nCycles>0 */
241         if (nCycles <= 0) nCycles = Long.MAX_VALUE;
242         jniter = new JNIter006[nJNI];
243         interval = jniInterval;
244         irupt = new Interrupter[nInter];
245         garb = new GarbageGenerator[nGarb];
246         for (i = 0; i < nJNI; i++)
247             jniter[i] = new JNIter006(sync);
248         for (i = 0; i < nInter; i++) {
249             irupt[i] = new Interrupter(jniter, sync);
250             irupt[i].setInterval(iruptInterval);
251         }
252         for (i = 0; i < nGarb; i++) {
253             garb[i] = new GarbageGenerator();
254             garb[i].setInterval(garbInterval);
255         }
256     }
257 
run()258     public void run() {
259         try {
260             int i = 0;
261             long iCycle = 0L;
262             JNIter006.clearCount();
263             JNIter006.clearInterruptCount();
264             for (i = 0; i < jniter.length; i++)
265                 jniter[i].start();
266 
267             while (JNIter006.getCount() < jniter.length) {
268                 try {
269                     sleep(100);
270                 } catch (InterruptedException e) {
271                 }
272             }
273             JNIter006.clearCount();
274             // JNIter006.clearInterruptCount();
275             synchronized (sync[0]) {
276                 sync[0].notifyAll();
277             }
278 
279             for (i = 0; i < garb.length; i++)
280                 garb[i].start();
281             for (i = 0; i < irupt.length; i++)
282                 irupt[i].start();
283 
284             if (DEBUG) System.out.println("Cycles=" + nCycles);
285             for (iCycle = 0; iCycle < nCycles && !done && JNIter006.passed(); iCycle++) {
286                 System.out.print("Cycle: " + iCycle);
287                 try {
288                     sleep(interval);
289                 } catch (InterruptedException e) {
290                 }
291                 synchronized (sync[1]) {
292                     System.out.println("  Interrupt count=" +
293                             JNIter006.getInterruptCount());
294                 }
295                 JNIter006.clearCount();
296                 synchronized (sync[0]) {
297                     sync[0].notifyAll();
298                 }
299                 int n = 0;
300                 for (i = 0; i < jniter.length; i++)
301                     if (jniter[i].finished()) n++;
302                 if (n == jniter.length) break;
303             }
304             if (JNIter006.passed())
305                 System.out.println("JNI TEST PASSED");
306             else
307                 System.out.println("JNI TEST FAILED");
308             for (i = 0; i < irupt.length; i++)
309                 irupt[i].halt();
310             for (i = 0; i < garb.length; i++)
311                 garb[i].halt();
312             for (i = 0; i < jniter.length; i++)
313                 jniter[i].halt();
314                         /* Flush any waiters */
315             if (DEBUG) System.out.println("jnistress006::run(): before sync[0]");
316             synchronized (sync[0]) {
317                 sync[0].notifyAll();
318             }
319             if (DEBUG) System.out.println("jnistress006::run(): after sync[0]");
320             for (i = 0; i < irupt.length; i++) {
321                 try {
322                     irupt[i].join();
323                 } catch (InterruptedException e) {
324                 }
325             }
326             if (DEBUG) System.out.println("jnistress006::run(): X");
327             for (i = 0; i < garb.length; i++) {
328                 try {
329                     garb[i].join();
330                 } catch (InterruptedException e) {
331                 }
332             }
333             if (DEBUG) System.out.println("jnistress006::run(): Y");
334             synchronized (sync[0]) {
335                 sync[0].notifyAll();
336             }
337             for (i = 0; i < jniter.length; i++) {
338                 try {
339                     if (jniter[i].isAlive()) {
340                         jniter[i].join();
341                     }
342                 } catch (InterruptedException e) {
343                 }
344             }
345             if (DEBUG) System.out.println("jnistress006::run(): Z");
346         } catch (Throwable e) {
347             Debug.Fail(e);
348         }
349     }
350 
halt()351     public void halt() {
352         done = true;
353     }
354 
finished()355     public boolean finished() {
356         return done;
357     }
358 
359     long nCycles = 0;
360     JNIter006[] jniter;
361     static Synchronizer[] sync;
362     private int interval = 100;
363     Interrupter[] irupt;
364     GarbageGenerator[] garb;
365     private boolean done = false;
366     final private static boolean DEBUG = false;
367 }
368 
369 class JNIter006 extends Thread {
370 
371     // The native methods for testing JNI exception calls
refs(Object tobj, int jniStringAllocSize)372     public native boolean refs(Object tobj, int jniStringAllocSize);
373 
374     static {
375         System.loadLibrary("jnistress006");
376     }
377 
378     Referenced tobj = new Referenced();
379     static int CountRefs;
380 
JNIter006(Synchronizer[] aSync)381     public JNIter006(Synchronizer[] aSync) {
382         sync = aSync;
383     }
384 
run()385     public void run() {
386         try {
387             int iter = 0;
388 
389                         /* Synchronize start of work */
390             incCount();
391             synchronized (sync[0]) {
392                 try {
393                     sync[0].wait();
394                 } catch (InterruptedException e) {
395                 }
396             }
397             while (!done && pass) {
398                 try {
399                                 /* Synchronized the JNI stressing */
400                     synchronized (sync[2]) {
401                         incCount();
402                     }
403                     synchronized (sync[0]) {
404                         try {
405                             sync[0].wait();
406                         } catch (InterruptedException e) {
407                             synchronized (sync[1]) {
408                                 JNIter006.incInterruptCount();
409                             }
410                         }
411                     }
412                     synchronized (sync[0]) {
413                         try {
414                             tobj.set_i(123456);
415                             pass = refs(tobj, jnistress006.jniStringAllocSize);
416                         } catch (Exception e) {
417                             System.out.println("Error: " + e);
418                         }
419                     }
420                     if (DEBUG)
421                         System.out.println("We have " + activeCount() + " threads now.");
422                     synchronized (this) {
423                         try {
424                             wait(1L);
425                         } catch (InterruptedException e) {
426                             throw new InterruptedException();
427                         }
428                     }
429                 } catch (Exception e) {
430                     synchronized (sync[1]) {
431                         JNIter006.incInterruptCount();
432                     }
433                 }
434                 iter++;
435                 iter = iter % CASECOUNT;
436             }
437             if (DEBUG) System.out.println("JNITer::run(): done=" + done);
438             done = true;
439             if (DEBUG) System.out.println("JNITer::run(): pass=" + JNIter006.pass);
440             if (DEBUG) System.out.println("JNIter006::run(): done");
441         } catch (Throwable e) {
442             Debug.Fail(e);
443         }
444     }
445 
incCount()446     private synchronized static void incCount() {
447         count++;
448     }
449 
getCount()450     public static int getCount() {
451         return count;
452     }
453 
clearCount()454     public synchronized static void clearCount() {
455         count = 0;
456     }
457 
incInterruptCount()458     private synchronized static void incInterruptCount() {
459         interruptCount++;
460     }
461 
getInterruptCount()462     public static int getInterruptCount() {
463         return interruptCount;
464     }
465 
clearInterruptCount()466     public synchronized static void clearInterruptCount() {
467         interruptCount = 0;
468     }
469 
halt()470     public void halt() {
471         done = true;
472     }
473 
finished()474     public boolean finished() {
475         return done;
476     }
477 
passed()478     public static boolean passed() {
479         return pass;
480     }
481 
482     Synchronizer[] sync;
483     private static int count = 0;
484     private static int interruptCount = 0;
485     private static boolean done = false;
486     private static boolean pass = true;
487     final private static int CASECOUNT = 2;
488     final private static boolean DEBUG = false;
489 }
490 
491 class Referenced {
492     private static int i;
493 
set_i(int value)494     public static void set_i(int value) {
495         i = value;
496     }
497 
get_i()498     public static int get_i() {
499         return i;
500     }
501 }
502