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