1 /* 2 * Copyright (c) 2001, 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.ThreadDeathEvent.thread; 25 26 import com.sun.jdi.*; 27 import com.sun.jdi.event.*; 28 import com.sun.jdi.request.*; 29 30 import java.io.*; 31 import java.util.Iterator; 32 33 import nsk.share.*; 34 import nsk.share.jpda.*; 35 import nsk.share.jdi.*; 36 37 38 // This class is the debugger in the test 39 40 public class thread001 { 41 static final int PASSED = 0; 42 static final int FAILED = 2; 43 static final int JCK_STATUS_BASE = 95; 44 45 static final int TIMEOUT_DELTA = 1000; // milliseconds 46 47 //synchronization commands 48 static final String COMMAND_READY = "ready"; 49 static final String COMMAND_QUIT = "quit"; 50 static final String COMMAND_GO = "go"; 51 static final String COMMAND_DONE = "done"; 52 static final String DEBUGGEE_NAME = "nsk.jdi.ThreadDeathEvent.thread.thread001a"; 53 54 // scaffold objects 55 static private Debugee debuggee; 56 static private VirtualMachine vm; 57 static private IOPipe pipe; 58 static private Log log; 59 static private ArgumentHandler argHandler; 60 static private EventSet eventSet; 61 62 static private ThreadDeathRequest checkedRequest; 63 // static private ThreadReference eventThread; 64 static private String checkedThreads [][] = { 65 {"innerThread","0"}, 66 {"innerDaemon","0"}, 67 {"outerThread","0"}, 68 {"outerDaemon","0"} 69 }; 70 71 static private long eventTimeout; 72 static private int eventsExpected; 73 static private int eventsReceived; 74 75 static volatile private boolean testFailed = false; 76 main(String args[])77 public static void main (String args[]) { 78 System.exit(run(args, System.out) + JCK_STATUS_BASE); 79 } 80 run(final String args[], final PrintStream out)81 public static int run(final String args[], final PrintStream out) { 82 83 testFailed = false; 84 eventsExpected = checkedThreads.length; 85 eventsReceived = 0; 86 87 argHandler = new ArgumentHandler(args); 88 log = new Log(out, argHandler); 89 eventTimeout = argHandler.getWaitTime() * 60 * 1000; // milliseconds 90 91 // launch and connect to debuggee 92 Binder binder = new Binder(argHandler, log); 93 log.display("Connecting to debuggee"); 94 debuggee = binder.bindToDebugee(DEBUGGEE_NAME); 95 debuggee.redirectStderr(log, "debuggee >"); 96 97 pipe = debuggee.createIOPipe(); 98 vm = debuggee.VM(); 99 100 // resume debuggee suspended at start up 101 log.display("Resuming debuggee"); 102 debuggee.resume(); 103 104 // perform the test, catch exceptions and finally quit debuggee 105 try { 106 107 // wait for debuggee started 108 log.display("Waiting for command: " + COMMAND_READY); 109 String command = pipe.readln(); 110 if (!command.equals(COMMAND_READY)) { 111 throw new Failure("TEST BUG: unexpected debuggee's command: " + command); 112 } 113 114 // create and enable event request 115 log.display("Creating request for ClassPrepareEvent"); 116 EventRequestManager erManager = debuggee.VM().eventRequestManager(); 117 if ((checkedRequest = erManager.createThreadDeathRequest()) == null) { 118 log.complain("TEST BUG: unable to create createThreadDeathRequest"); 119 pipe.println(COMMAND_QUIT); 120 debuggee.waitFor(); 121 return thread001.FAILED; 122 } 123 checkedRequest.enable(); 124 125 // define separate thread for handling events 126 class EventHandler extends Thread { 127 public void run() { 128 eventSet = null; 129 try { 130 eventHandlingLoop: 131 while (eventsReceived < eventsExpected) { 132 eventSet = vm.eventQueue().remove(); 133 134 EventIterator eventIterator = eventSet.eventIterator(); 135 while (eventIterator.hasNext()) { 136 137 Event event = eventIterator.nextEvent(); 138 log.display("\nEvent received:\n " + event); 139 140 // handle ThreadDeathEvent 141 if (event instanceof ThreadDeathEvent) { 142 log.display("\nThreadDeathEvent received"); 143 ThreadDeathEvent castedEvent = (ThreadDeathEvent)event; 144 145 EventRequest eventRequest = castedEvent.request(); 146 if (!(checkedRequest.equals(eventRequest))) { 147 log.complain("FAILURE 1: eventRequest is not equal to checked request"); 148 testFailed = true; 149 } 150 VirtualMachine eventMachine = castedEvent.virtualMachine(); 151 if (!(vm.equals(eventMachine))) { 152 log.complain("FAILURE 2: eventVirtualMachine is not equal to checked vm"); 153 testFailed = true; 154 } 155 156 ThreadReference eventThread = ((ThreadDeathEvent)event).thread(); 157 if (eventThread == null) { 158 log.complain("FAILURE 2: ThreadDeathEvent.thread() returns null"); 159 testFailed = true; 160 } 161 162 String threadName = eventThread.name(); 163 if ((threadName == null) || (threadName.equals(""))) { 164 log.complain("FAILURE 3: thread reference has invalid empty name"); 165 testFailed = true; 166 } else { 167 log.display ("Expected ThreadDeathEvent was received for " + threadName); 168 } 169 170 // Check that all expected debuggee's thread create ThreadDeathEvent only once 171 eventsReceived = 0; 172 for (int i = 0; i < checkedThreads.length; i++) { 173 if (threadName.equals(checkedThreads[i][0])) { 174 if (checkedThreads[i][1].equals("0")) { 175 checkedThreads[i][1] = "1"; 176 } else { 177 log.complain("FAILURE 5: ThreadDeathEvent for " + threadName + " is received more that once"); 178 testFailed = true; 179 } 180 } 181 if (checkedThreads[i][1].equals("1")) { 182 eventsReceived++; 183 } 184 } 185 } 186 187 // ignore each other events 188 189 } // end of event handling loop 190 191 // log.display("Resuming event set"); 192 eventSet.resume(); 193 194 } // end of event set handling loop 195 196 } catch (InterruptedException e) { 197 log.complain("TEST INCOMPLETE: caught InterruptionException while waiting for event"); 198 } catch (VMDisconnectedException e) { 199 log.complain("TEST INCOMPLETE: caught VMDisconnectedException while waiting for event"); 200 testFailed = true; 201 } 202 203 log.display("Disabling event request"); 204 checkedRequest.disable(); 205 206 log.display("eventHandler completed"); 207 208 } // end of run() 209 210 } // end of EventHandler 211 212 // start EventHandler thread 213 EventHandler eventHandler = new EventHandler(); 214 log.display("Starting eventHandler"); 215 eventHandler.start(); 216 217 // force debuggee to quit 218 log.display("Sending command: " + COMMAND_GO); 219 pipe.println(COMMAND_GO); 220 221 // wait for all tested threads completed 222 command = pipe.readln(); 223 if (!command.equals(COMMAND_DONE)) { 224 throw new Failure("TEST BUG: unexpected debuggee's command: " + command); 225 } 226 227 log.display(""); 228 229 // wait for all expected events received or timeout exceeds 230 log.display("Waiting for all expected events received"); 231 try { 232 eventHandler.join(eventTimeout); 233 if (eventHandler.isAlive()) { 234 log.complain("FAILURE 20: Timeout for waiting event was exceeded"); 235 eventHandler.interrupt(); 236 testFailed = true; 237 } 238 } catch (InterruptedException e) { 239 log.complain("TEST INCOMPLETE: InterruptedException caught while waiting for eventHandler's death"); 240 testFailed = true; 241 } 242 243 // Check that all expected debuggee's thread created ThreadDeathEvent 244 for (int i = 0; i < checkedThreads.length; i++) { 245 if (checkedThreads[i][1].equals("0")) { 246 log.complain("FAILURE 1: ThreadDeathEvent for thread " + checkedThreads[i][0] + " is not received"); 247 testFailed = true; 248 } 249 } 250 251 } catch (Failure e) { 252 log.complain("TEST FAILURE: " + e.getMessage()); 253 testFailed = true; 254 } catch (Exception e) { 255 log.complain("TEST FAILURE: Unexpected exception: " + e); 256 e.printStackTrace(out); 257 testFailed = true; 258 } finally { 259 log.display(""); 260 261 // force debugee to exit 262 log.display("Sending command: " + COMMAND_QUIT); 263 pipe.println(COMMAND_QUIT); 264 265 // wait for debuggee exits and analize its exit code 266 log.display("Waiting for debuggee terminating"); 267 int debuggeeStatus = debuggee.endDebugee(); 268 if (debuggeeStatus == PASSED + JCK_STATUS_BASE) { 269 log.display("Debuggee PASSED with exit code: " + debuggeeStatus); 270 } else { 271 log.complain("Debuggee FAILED with exit code: " + debuggeeStatus); 272 testFailed = true; 273 } 274 } 275 276 // check test results 277 if (testFailed) { 278 log.complain("TEST FAILED"); 279 return FAILED; 280 } 281 282 log.display("TEST PASSED"); 283 return PASSED; 284 } 285 } 286