1 /*
2  * Copyright (c) 2002, 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 package nsk.jdi.ObjectReference.owningThread;
25 
26 import nsk.share.*;
27 import nsk.share.jpda.*;
28 import nsk.share.jdi.*;
29 
30 import com.sun.jdi.*;
31 import com.sun.jdi.connect.*;
32 import com.sun.jdi.request.*;
33 import com.sun.jdi.event.*;
34 import java.io.*;
35 import java.util.*;
36 
37 /**
38  */
39 public class owningthread002 {
40 
41     //----------------------------------------------------- immutable common fields
42 
43     static final int PASSED    = 0;
44     static final int FAILED    = 2;
45     static final int PASS_BASE = 95;
46     static final int quit      = -1;
47 
48     private int instruction = 1;
49     private int waitTime;
50     private static int exitCode = PASSED;
51 
52     private ArgumentHandler     argHandler;
53     private Log                 log;
54     private Debugee             debuggee;
55     private VirtualMachine      vm;
56     private ReferenceType       debuggeeClass;
57 
58     private EventRequestManager eventRManager;
59     private EventSet            eventSet;
60     private EventIterator       eventIterator;
61 
62     //------------------------------------------------------ mutable common fields
63 
64     private final static String prefix = "nsk.jdi.ObjectReference.owningThread.";
65     private final static String className = "owningthread002";
66     private final static String debuggerName = prefix + className;
67     private final static String debuggeeName = debuggerName + "a";
68     static final int lineForBreak = 62;
69 
70     //------------------------------------------------------ immutable common methods
71 
main(String argv[])72     public static void main (String argv[]) {
73         System.exit(run(argv, System.out) + PASS_BASE);
74     }
75 
76     //------------------------------------------------------ test specific fields
77 
78     //------------------------------------------------------ mutable common methods
79 
run(String argv[], PrintStream out)80     public static int run (String argv[], PrintStream out) {
81 
82         int exitStatus = new owningthread002().runThis(argv, out);
83         System.out.println (exitStatus == PASSED ? "TEST PASSED" : "TEST FAILED");
84         return exitCode;
85     }
86 
runThis(String argv[], PrintStream out)87     private int runThis(String argv[], PrintStream out) {
88 
89         argHandler = new ArgumentHandler(argv);
90         log = new Log(out, argHandler);
91         waitTime = argHandler.getWaitTime() * 60000;
92 
93         try {
94 
95             Binder binder = new Binder(argHandler, log);
96             debuggee = binder.bindToDebugee(debuggeeName);
97             debuggee.redirectStderr(log, "");
98             eventRManager = debuggee.getEventRequestManager();
99 
100             vm = debuggee.VM();
101             eventRManager = vm.eventRequestManager();
102 
103             debuggeeClass = waitForDebuggeeClassPrepared();
104 
105             execTest();
106 
107             debuggee.resume();
108             getEventSet();
109             if (eventIterator.nextEvent() instanceof VMDeathEvent) {
110                 display("Waiting for the debuggee's finish...");
111                 debuggee.waitFor();
112 
113                 display("Getting the debuggee's exit status.");
114                 int status = debuggee.getStatus();
115                 if (status != (PASSED + PASS_BASE)) {
116                     complain("Debuggee returned UNEXPECTED exit status: " + status);
117                     exitCode = Consts.TEST_FAILED;
118                 }
119             } else {
120                 throw new TestBug("Last event is not the VMDeathEvent");
121             }
122 
123         } catch (VMDisconnectedException e) {
124             exitCode = Consts.TEST_FAILED;
125             complain("The test cancelled due to VMDisconnectedException.");
126             e.printStackTrace(out);
127             display("Trying: vm.process().destroy();");
128             if (vm != null) {
129                 Process vmProcess = vm.process();
130                 if (vmProcess != null) {
131                     vmProcess.destroy();
132                 }
133             }
134 
135         } catch (Exception e) {
136             exitCode = Consts.TEST_FAILED;
137             complain("Unexpected Exception: " + e.getMessage());
138             e.printStackTrace(out);
139             complain("The test has not finished normally. Forcing: vm.exit().");
140             if (vm != null) {
141                 vm.exit(PASSED + PASS_BASE);
142             }
143             debuggee.resume();
144             getEventSet();
145         }
146 
147         return exitCode;
148     }
149 
150     //--------------------------------------------------------- mutable common methods
151 
execTest()152     private void execTest() {
153         ThreadReference mainThread = debuggee.threadByName("main");
154 
155         BreakpointRequest bpRequest = debuggee.makeBreakpoint(debuggeeClass,
156                                                              "methodForCommunication",
157                                                              lineForBreak);
158         bpRequest.addThreadFilter(mainThread);
159         bpRequest.putProperty("number", "breakpointForCommunication");
160         bpRequest.enable();
161 
162         display("TESTING BEGINS");
163 
164         label0:
165         for (int testCase = 0; instruction != quit; testCase++) {
166 
167             waitForEvent(bpRequest);
168             instruction = getInstruction();
169             if (instruction == quit) {
170                 vm.resume();
171                 break;
172             }
173 
174             display(":: case: # " + testCase);
175 
176             switch (testCase) {
177             //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ test case section
178                  case 0:
179 
180                      if (vm.canGetMonitorInfo()) {
181                          // create method entry request to track the moments of locking of owningthread002.lockObj
182                          MethodEntryRequest meRequest = eventRManager.createMethodEntryRequest();
183                          meRequest.addClassFilter(debuggeeName + "Lock");
184                          meRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD );
185                          meRequest.enable();
186                          display("methodEntryRequest is enabled ");
187 
188                          String fieldName = "lockObj";
189                          ObjectReference lockRef = (ObjectReference) debuggeeClass.getValue(debuggeeClass.fieldByName(fieldName));
190 
191                          for (int i = 1; i <= owningthread002a.threadCount; i++) {
192 
193                              Event meEvent = waitForEvent(meRequest);
194                              ThreadReference eventThread = ((LocatableEvent)meEvent).thread();
195                              display("Checking owningThread method after MethodEntryEvent in thread : " + eventThread );
196 
197                              try {
198                                  ThreadReference thread = lockRef.owningThread();
199 
200                                  if (thread.name().indexOf(owningthread002a.threadNamePrefix) < 0) {
201                                      exitCode = Consts.TEST_FAILED;
202                                      complain("owningThread returned ThreadReference with unexpected name: " + thread.name());
203                                  }
204                                  if (!eventThread.equals(thread)) {
205                                      exitCode = Consts.TEST_FAILED;
206                                      complain("owningThread returned unexpected ThreadReference : " + thread +
207                                          "\n\t expected ThreadReference returned by MethodEntryEvent.thread() : " + eventThread );
208                                  } else {
209                                      display("Expected ThreadReference is returned by owningThread method: " + thread.name());
210                                  }
211 
212                              } catch (Exception e) {
213                                  throw new Failure("Unexpected exception while invoking owningThread method: " + e);
214                              }
215                          }
216                          meRequest.disable();
217                      }
218                      break;
219 
220             //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ end of section
221                  default:
222                      instruction = quit;
223                      setInstruction("quit");
224             }
225         }
226         display("TESTING ENDS");
227     }
228 
229     //--------------------------------------------------------- test specific methodss
230 
231     //--------------------------------------------------------- immutable common methods
232 
display(String msg)233     void display(String msg) {
234         log.display("debugger > " + msg);
235     }
236 
complain(String msg)237     void complain(String msg) {
238         log.complain("debugger FAILURE > " + msg);
239     }
240 
waitForEvent(EventRequest eventRequest)241     private Event waitForEvent (EventRequest eventRequest) {
242 
243         vm.resume();
244         Event resultEvent = null;
245         try {
246             eventSet = null;
247             eventIterator = null;
248             eventSet = vm.eventQueue().remove(waitTime);
249             if (eventSet == null) {
250                 throw new Failure("TIMEOUT while waiting for an event");
251             }
252             eventIterator = eventSet.eventIterator();
253             while (eventIterator.hasNext()) {
254                 Event curEvent = eventIterator.nextEvent();
255                 if (curEvent instanceof VMDisconnectEvent) {
256                     throw new Failure("Unexpected VMDisconnectEvent received.");
257                 } else {
258                     EventRequest evRequest = curEvent.request();
259                     if (evRequest != null && evRequest.equals(eventRequest)) {
260                         display("Requested event received: " + curEvent.toString() +
261                             "; request property: " + (String) curEvent.request().getProperty("number"));
262                         resultEvent = curEvent;
263                         break;
264                     } else {
265                         throw new Failure("Unexpected event received: " + curEvent.toString());
266                     }
267                 }
268             }
269         } catch (Exception e) {
270             throw new Failure("Unexpected exception while waiting for an event: " + e);
271         }
272         return resultEvent;
273     }
274 
275 
getEventSet()276     private void getEventSet() {
277         try {
278             eventSet = vm.eventQueue().remove(waitTime);
279             if (eventSet == null) {
280                 throw new Failure("TIMEOUT while waiting for an event");
281             }
282             eventIterator = eventSet.eventIterator();
283         } catch (Exception e) {
284             throw new Failure("getEventSet(): Unexpected exception while waiting for an event: " + e);
285         }
286     }
287 
waitForDebuggeeClassPrepared()288     private ReferenceType waitForDebuggeeClassPrepared () {
289         display("Creating request for ClassPrepareEvent for debuggee.");
290         ClassPrepareRequest cpRequest = eventRManager.createClassPrepareRequest();
291         cpRequest.addClassFilter(debuggeeName);
292         cpRequest.addCountFilter(1);
293         cpRequest.enable();
294 
295         ClassPrepareEvent event = (ClassPrepareEvent) waitForEvent(cpRequest);
296         cpRequest.disable();
297 
298         if (!event.referenceType().name().equals(debuggeeName)) {
299            throw new Failure("Unexpected class name for ClassPrepareEvent : " + debuggeeClass.name());
300         }
301         return event.referenceType();
302     }
303 
getInstruction()304     private int getInstruction () {
305         if (debuggeeClass == null) {
306             throw new Failure("getInstruction() :: debuggeeClass reference is null");
307         }
308         return ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value();
309     }
310 
setInstruction(String instructionField)311     private void setInstruction (String instructionField) {
312         if (debuggeeClass == null) {
313             throw new Failure("getInstruction() :: debuggeeClass reference is null");
314         }
315         Field instrField = debuggeeClass.fieldByName("instruction");
316         IntegerValue instrValue = (IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName(instructionField)));
317         try {
318             ((ClassType)debuggeeClass).setValue(instrField, instrValue );
319         } catch (InvalidTypeException e1) {
320             throw new Failure("Caught unexpected InvalidTypeException while setting value '" + instructionField + "' for instruction field");
321         } catch (ClassNotLoadedException e2) {
322             throw new Failure("Caught unexpected ClassNotLoadedException while setting value '" + instructionField + "' for instruction field");
323         }
324     }
325 }
326