1 /*
2  * Copyright (c) 2001, 2019, 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 package nsk.jdi.VirtualMachine.suspend;
25 
26 import jdk.test.lib.Utils;
27 import nsk.share.*;
28 import nsk.share.jpda.*;
29 import nsk.share.jdi.*;
30 
31 import com.sun.jdi.*;
32 import java.util.*;
33 import java.io.*;
34 
35 import com.sun.jdi.event.*;
36 import com.sun.jdi.request.*;
37 
38 /**
39  * The test for the implementation of an object of the type     <BR>
40  * VirtualMachine.                                              <BR>
41  *                                                              <BR>
42  * The test checks up that results of the method                <BR>
43  * <code>com.sun.jdi.VirtualMachine.suspend()</code>            <BR>
44  * complies with its spec.                                      <BR>
45  * <BR>
46  * The cases for testing are as follows.                                <BR>
47  * After being started up,                                              <BR>
48  * a debuggee creates a 'lockingObject' for synchronizing threads,      <BR>
49  * enters a synchronized block in which it creates new thread, thread2, <BR>
50  * informs a debugger of the thread2 creation, and is waiting for reply.<BR>
51  * Since thread2 uses the same locking object in its 'run' method       <BR>
52  * it is locked up until first thread leaves the synchronized block.    <BR>
53  * Upon the receiption a message from the debuggee, the debugger :      <BR>
54  * - sets up breakpoints for both thread2 and main thread in the debuggee,<BR>
55  * - gets both threads suspended at the breakpoints,                    <BR>
56  * - calls to the method VirtualMachine.suspend(),                      <BR>
57  * - resumes both threads individually, one time each,                  <BR>
58  * - sleeps for predefined time - a standard parameter of the test,     <BR>
59  * - then checks up the value of debuggee's field "flagCount" which is  <BR>
60  *   incremented by both tested threads only after their points of      <BR>
61  *   suspension. Hence, if the value == 0 (initial), it has not been    <BR>
62  *   changed by any tested thread while the debugger has been sleeping. <BR>
63  */
64 
65 public class suspend001 {
66 
67     //----------------------------------------------------- templete section
68     static final int PASSED = 0;
69     static final int FAILED = 2;
70     static final int PASS_BASE = 95;
71 
72     //----------------------------------------------------- templete parameters
73     static final String
74     sHeader1 = "\n==> nsk/jdi/VirtualMachine/suspend/suspend001  ",
75     sHeader2 = "--> debugger: ",
76     sHeader3 = "##> debugger: ";
77 
78     //----------------------------------------------------- main method
79 
main(String argv[])80     public static void main (String argv[]) {
81         int result = run(argv, System.out);
82         System.exit(result + PASS_BASE);
83     }
84 
run(String argv[], PrintStream out)85     public static int run (String argv[], PrintStream out) {
86         return new suspend001().runThis(argv, out);
87     }
88 
89     //--------------------------------------------------   log procedures
90 
91     private static Log  logHandler;
92 
log1(String message)93     private static void log1(String message) {
94         logHandler.display(sHeader1 + message);
95     }
log2(String message)96     private static void log2(String message) {
97         logHandler.display(sHeader2 + message);
98     }
log3(String message)99     private static void log3(String message) {
100         logHandler.complain(sHeader3 + message);
101     }
102 
103     //  ************************************************    test parameters
104 
105     private String debuggeeName =
106         "nsk.jdi.VirtualMachine.suspend.suspend001a";
107 
108     private String testedClassName =
109         "nsk.jdi.VirtualMachine.suspend.VMsuspend001a";
110 
111     //String mName = "nsk.jdi.VirtualMachine.suspend";
112 
113     //====================================================== test program
114     //------------------------------------------------------ common section
115 
116     static ArgumentHandler      argsHandler;
117 
118     static int waitTime;
119 
120     static VirtualMachine      vm            = null;
121     static EventRequestManager eventRManager = null;
122     static EventQueue          eventQueue    = null;
123     static EventSet            eventSet      = null;
124 
125     ReferenceType     testedclass  = null;
126     ThreadReference   thread2      = null;
127     ThreadReference   mainThread   = null;
128 
129     static int  testExitCode = PASSED;
130 
131     static final int returnCode0 = 0;
132     static final int returnCode1 = 1;
133     static final int returnCode2 = 2;
134     static final int returnCode3 = 3;
135     static final int returnCode4 = 4;
136 
137     //------------------------------------------------------ methods
138 
runThis(String argv[], PrintStream out)139     private int runThis (String argv[], PrintStream out) {
140 
141         Debugee debuggee;
142 
143         argsHandler     = new ArgumentHandler(argv);
144         logHandler      = new Log(out, argsHandler);
145         Binder binder   = new Binder(argsHandler, logHandler);
146 
147         if (argsHandler.verbose()) {
148             debuggee = binder.bindToDebugee(debuggeeName + " -vbs");
149         } else {
150             debuggee = binder.bindToDebugee(debuggeeName);
151         }
152 
153         waitTime = argsHandler.getWaitTime();
154 
155 
156         IOPipe pipe     = new IOPipe(debuggee);
157 
158         debuggee.redirectStderr(out);
159         log2(debuggeeName + " debuggee launched");
160         debuggee.resume();
161 
162         String line = pipe.readln();
163         if ((line == null) || !line.equals("ready")) {
164             log3("signal received is not 'ready' but: " + line);
165             return FAILED;
166         } else {
167             log2("'ready' recieved");
168         }
169 
170         vm = debuggee.VM();
171 
172     //------------------------------------------------------  testing section
173         log1("      TESTING BEGINS");
174 
175         for (int i = 0; ; i++) {
176 
177             pipe.println("newcheck");
178             line = pipe.readln();
179 
180             if (line.equals("checkend")) {
181                 log2("     : returned string is 'checkend'");
182                 break ;
183             } else if (!line.equals("checkready")) {
184                 log3("ERROR: returned string is not 'checkready'");
185                 testExitCode = FAILED;
186                 break ;
187             }
188 
189             log1("new checkready: #" + i);
190 
191             //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ variable part
192 
193             int expresult = returnCode0;
194 
195             eventRManager = vm.eventRequestManager();
196             eventQueue    = vm.eventQueue();
197 
198             String threadName = "Thread2";
199             String flagName   = "flagCount";
200 
201             String breakpointMethod1 = "runt1";
202             String breakpointMethod2 = "runt2";
203 
204             String bpLine1 = "breakpointLineNumber1";
205             String bpLine2 = "breakpointLineNumber2";
206 
207             List            allThreads   = null;
208             ListIterator    listIterator = null;
209             List            classes      = null;
210 
211             BreakpointRequest breakpRequest1 = null;
212             BreakpointRequest breakpRequest2 = null;
213 
214 
215             label0: {
216 
217                 log2("getting ThreadReference objects and setting up breakponts");
218                 try {
219                     allThreads  = vm.allThreads();
220                     classes     = vm.classesByName(testedClassName);
221                     testedclass = (ReferenceType) classes.get(0);
222                 } catch ( Exception e) {
223                     log3("ERROR: Exception at very beginning !? : " + e);
224                     expresult = returnCode1;
225                     break label0;
226                 }
227 
228                 listIterator = allThreads.listIterator();
229                 for (;;) {
230                     try {
231                         thread2 = (ThreadReference) listIterator.next();
232                         if (thread2.name().equals(threadName))
233                             break ;
234                     } catch ( NoSuchElementException e ) {
235                         log3("ERROR: NoSuchElementException for listIterator.next()");
236                         log3("ERROR: NO THREAD2 ?????????!!!!!!!");
237                         expresult = returnCode1;
238                         break label0;
239                     }
240                 }
241                 listIterator = allThreads.listIterator();
242                 for (;;) {
243                     try {
244                         mainThread = (ThreadReference) listIterator.next();
245                         if (mainThread.name().equals("main"))
246                             break ;
247                     } catch ( NoSuchElementException e ) {
248                         log3("ERROR: NoSuchElementException for listIterator.next()");
249                         log3("ERROR: NO THREAD2 ?????????!!!!!!!");
250                         expresult = returnCode1;
251                         break label0;
252                     }
253                 }
254 
255                 log2("setting up breakpoints");
256 
257                 breakpRequest1 = settingBreakpoint(breakpointMethod1, bpLine1, "one");
258                 if (breakpRequest1 == null) {
259                     expresult = returnCode1;
260                     break label0;
261                 }
262                 breakpRequest2 = settingBreakpoint(breakpointMethod2, bpLine2, "two");
263                 if (breakpRequest2 == null) {
264                     expresult = returnCode1;
265                     break label0;
266                 }
267             }
268 
269             label1: {
270                 if (expresult != returnCode0)
271                     break label1;
272 
273                 log2("       enabling breakpRequest1");
274                 breakpRequest1.enable();
275 
276                 log2("       instructing the main thread to leave synchronized block");
277                 pipe.println("continue");
278                 line = pipe.readln();
279                 if (!line.equals("docontinue")) {
280                     log3("ERROR: returned string is not 'docontinue'");
281                     expresult = returnCode4;
282                     break label1;
283                 }
284 
285                 log2("       getting BreakpointEvent");
286                 expresult = breakpoint();
287                 if (expresult != returnCode0)
288                     break label1;
289                 log2("       thread2 is at breakpoint");
290 
291                 log2("      copying: EventSet eventSet1 = eventSet;");
292                 EventSet eventSet1 = eventSet;
293 
294                 log2("       enabling breakpRequest2");
295                 breakpRequest2.enable();
296 
297                 log2("       instructing the main thread to leave to continue");
298                 pipe.println("continue");
299                 line = pipe.readln();
300                 if (!line.equals("docontinue")) {
301                     log3("ERROR: returned string is not 'docontinue'");
302                     expresult = returnCode4;
303                     break label1;
304                 }
305 
306                 log2("       getting BreakpointEvent");
307                 expresult = breakpoint();
308                 if (expresult != returnCode0)
309                     break label1;
310                 log2("       mainThread is at breakpoint");
311 
312                 log2("       debugger turned off pipe pinging");
313                 pipe.setPingTimeout(0);
314 
315                 log2("       suspending VM");
316                 vm.suspend();
317 
318                 log2("       resuming threads individually: eventSet1.resume(); eventSet.resume();");
319                 eventSet1.resume();
320                 eventSet.resume();
321 
322                 log2("       before: Thread.sleep(waitTime*1000);");
323 
324                 try {
325                     Thread.sleep(Utils.adjustTimeout(waitTime*1000));
326                 } catch ( InterruptedException e ) {
327                     log3("ERROR: InterruptedException");
328                     expresult = returnCode1;
329                     break label1;
330                 }
331 
332                 log2("       checking up debuggee's flagCount value");
333                 int flag = ((IntegerValue) testedclass.getValue(testedclass.fieldByName(flagName))).value();
334                 log2("        value of flagCount == " + flag);
335                 if (flag != 0) {
336                     log3("ERROR: value of flagCount != 0");
337                     expresult = returnCode1;
338                 }
339             }
340 
341             log2("      resuming VM");
342             vm.resume();
343 
344             //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
345             log2("     the end of testing");
346             if (expresult != returnCode0)
347                 testExitCode = FAILED;
348         }
349         log1("      TESTING ENDS");
350 
351     //--------------------------------------------------   test summary section
352     //-------------------------------------------------    standard end section
353 
354         pipe.println("quit");
355         log2("waiting for the debuggee to finish ...");
356         debuggee.waitFor();
357 
358         int status = debuggee.getStatus();
359         if (status != PASSED + PASS_BASE) {
360             log3("debuggee returned UNEXPECTED exit status: " +
361                     status + " != PASS_BASE");
362             testExitCode = FAILED;
363         } else {
364             log2("debuggee returned expected exit status: " +
365                     status + " == PASS_BASE");
366         }
367 
368         if (testExitCode != PASSED) {
369             logHandler.complain("TEST FAILED");
370         }
371         return testExitCode;
372     }
373 
374 
375    /*
376     * private BreakpointRequest settingBreakpoint(String, String, String)
377     *
378     * It sets up a breakpoint within a given method at given line number
379     * for the thread2 only.
380     * Third parameter is required for any case in future debugging, as if.
381     *
382     * Return codes:
383     *  = BreakpointRequest object  in case of success
384     *  = null   in case of an Exception thrown within the method
385     */
386 
settingBreakpoint( String methodName, String bpLine, String property)387     private BreakpointRequest settingBreakpoint ( String methodName,
388                                                   String bpLine,
389                                                   String property) {
390 
391         log2("setting up a breakpoint: method: '" + methodName + "' line: " + bpLine );
392 
393         List              alllineLocations = null;
394         Location          lineLocation     = null;
395         BreakpointRequest breakpRequest    = null;
396 
397         try {
398             Method  method  = (Method) testedclass.methodsByName(methodName).get(0);
399 
400             alllineLocations = method.allLineLocations();
401 
402             int n =
403                 ( (IntegerValue) testedclass.getValue(testedclass.fieldByName(bpLine) ) ).value();
404             if (n > alllineLocations.size()) {
405                 log3("ERROR:  TEST_ERROR_IN_settingBreakpoint(): number is out of bound of method's lines");
406             } else {
407                 lineLocation = (Location) alllineLocations.get(n);
408                 try {
409                     breakpRequest = eventRManager.createBreakpointRequest(lineLocation);
410                     breakpRequest.putProperty("number", property);
411 //                    breakpRequest.addThreadFilter(thread2);
412                     breakpRequest.setSuspendPolicy( EventRequest.SUSPEND_EVENT_THREAD);
413                 } catch ( Exception e1 ) {
414                     log3("ERROR: inner Exception within settingBreakpoint() : " + e1);
415                     breakpRequest    = null;
416                 }
417             }
418         } catch ( Exception e2 ) {
419             log3("ERROR: ATTENTION:  outer Exception within settingBreakpoint() : " + e2);
420             breakpRequest    = null;
421         }
422 
423         if (breakpRequest == null)
424             log2("      A BREAKPOINT HAS NOT BEEN SET UP");
425         else
426             log2("      a breakpoint has been set up");
427 
428         return breakpRequest;
429     }
430 
431 
432     /*
433      * private int breakpoint ()
434      *
435      * It removes events from EventQueue until gets first BreakpointEvent.
436      * To get next EventSet value, it uses the method
437      *    EventQueue.remove(int timeout)
438      * The timeout argument passed to the method, is "waitTime*60000".
439      * Note: the value of waitTime is set up with
440      *       the method ArgumentHandler.getWaitTime() at the beginning of the test.
441      *
442      * Return codes:
443      *  = returnCode0 - success;
444      *  = returnCode2 - Exception when "eventSet = eventQueue.remove()" is executed
445      *  = returnCode3 - default case when loop of processing an event, that is,
446      *                  an unspecified event was taken from the EventQueue
447      */
448 
breakpoint()449     private int breakpoint () {
450 
451         int returnCode = returnCode0;
452 
453         log2("       waiting for BreakpointEvent");
454 
455         labelBP:
456             for (;;) {
457 
458                 log2("       new:  eventSet = eventQueue.remove();");
459                 try {
460                     eventSet = eventQueue.remove (waitTime*60000);
461                     if (eventSet == null) {
462 //                        log2("::::::  timeout when waiting for a BreakpintEvent");
463                         log3("ERROR:  timeout for waiting for a BreakpintEvent");
464                         returnCode = returnCode3;
465                         break labelBP;
466                     }
467                 } catch ( Exception e ) {
468                     log3("ERROR: Exception for  eventSet = eventQueue.remove(); : " + e);
469                     returnCode = 1;
470                     break labelBP;
471                 }
472 
473                 if (eventSet != null) {
474 
475                     log2("     :  eventSet != null;  size == " + eventSet.size());
476 
477                     EventIterator eIter = eventSet.eventIterator();
478                     Event         ev    = null;
479 
480                     for (; eIter.hasNext(); ) {
481 
482                         if (returnCode != returnCode0)
483                             break;
484 
485                         ev = eIter.nextEvent();
486 
487                     ll: for (int ifor =0;  ; ifor++) {
488 
489                         try {
490                           switch (ifor) {
491 
492                           case 0:  AccessWatchpointEvent awe = (AccessWatchpointEvent) ev;
493                                    log2("      AccessWatchpointEvent removed");
494                                    break ll;
495                           case 1:  BreakpointEvent be = (BreakpointEvent) ev;
496                                    log2("      BreakpointEvent removed");
497                                    break labelBP;
498                           case 2:  ClassPrepareEvent cpe = (ClassPrepareEvent) ev;
499                                    log2("      ClassPreparEvent removed");
500                                    break ll;
501                           case 3:  ClassUnloadEvent cue = (ClassUnloadEvent) ev;
502                                    log2("      ClassUnloadEvent removed");
503                                    break ll;
504                           case 4:  ExceptionEvent ee = (ExceptionEvent) ev;
505                                    log2("      ExceptionEvent removed");
506                                    break ll;
507                           case 5:  MethodEntryEvent mene = (MethodEntryEvent) ev;
508                                    log2("      MethodEntryEvent removed");
509                                    break ll;
510                           case 6:  MethodExitEvent mexe = (MethodExitEvent) ev;
511                                    log2("      MethodExiEvent removed");
512                                    break ll;
513                           case 7:  ModificationWatchpointEvent mwe = (ModificationWatchpointEvent) ev;
514                                    log2("      ModificationWatchpointEvent removed");
515                                    break ll;
516                           case 8:  StepEvent se = (StepEvent) ev;
517                                    log2("      StepEvent removed");
518                                    break ll;
519                           case 9:  ThreadDeathEvent tde = (ThreadDeathEvent) ev;
520                                    log2("      ThreadDeathEvent removed");
521                                    break ll;
522                           case 10: ThreadStartEvent tse = (ThreadStartEvent) ev;
523                                    log2("      ThreadStartEvent removed");
524                                    break ll;
525                           case 11: VMDeathEvent vmde = (VMDeathEvent) ev;
526                                    log2("      VMDeathEvent removed");
527                                    break ll;
528                           case 12: VMStartEvent vmse = (VMStartEvent) ev;
529                                    log2("      VMStartEvent removed");
530                                    break ll;
531                           case 13: WatchpointEvent we = (WatchpointEvent) ev;
532                                    log2("      WatchpointEvent removed");
533                                    break ll;
534 
535                           default: log3("ERROR:  default case for casting event");
536                                    returnCode = returnCode3;
537                                    break ll;
538                           } // switch
539                         } catch ( ClassCastException e ) {
540                         }   // try
541                     }       // ll: for (int ifor =0;  ; ifor++)
542                 }           // for (; ev.hasNext(); )
543             }
544         }
545         if (returnCode == returnCode0)
546             log2("     :  eventSet == null:  EventQueue is empty");
547 
548         return returnCode;
549     }
550 
551 }
552