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