Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventHandler.java
41161 views
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.share.jdi;
25
26
import java.util.*;
27
import com.sun.jdi.*;
28
import com.sun.jdi.event.*;
29
import com.sun.jdi.request.*;
30
import nsk.share.*;
31
32
/**
33
* This class provides a separate thread for asynchronous listening
34
* to JDI events. All received events are sequentially passed
35
* to event listeners. If current event listener returns true
36
* then the event is considered be processed and it is not passed
37
* to remaining listeners.
38
* <p>
39
* The <code>EventHandler</code> thread runs until <code>VMDisconnectEvent</code>
40
* is received or <code>VMDisconnectionedException</code> is caught.
41
*
42
* @see EventListener
43
*/
44
public class EventHandler implements Runnable {
45
46
private Debugee debuggee = null;
47
private Log log = null;
48
49
private VirtualMachine vm;
50
private EventRequestManager requestManager;
51
/**
52
* Container for event listeners
53
*/
54
private static List<EventListener> listeners = Collections.synchronizedList(new Vector<EventListener>());
55
private Thread listenThread;
56
57
/**
58
* Exit status of the <code>EventHandler</code> thread
59
*/
60
private static volatile int status = -1;
61
62
/**
63
* Return an exit status of the <code>EventHandler</code> thread
64
* were the values are:
65
* <li><i>-1</i> - no value
66
* <li><i>0</i> - normal termination
67
* <li><i>1</i> - the thread is still running
68
* <li><i>2</i> - abnormal termination
69
*/
70
public static synchronized int getStatus() {
71
return status;
72
}
73
74
/**
75
* Default ExceptionRequest with SUSPEND_EVENT_THREAD to be able
76
* to catch debuggee exceptions and output a message.
77
*/
78
private static ExceptionRequest defaultExceptionRequest = null;
79
80
/**
81
* This flag will be set true if event of uncaught exception has been
82
* received.
83
*/
84
private static volatile boolean defaultExceptionCaught = false;
85
public static synchronized boolean getExceptionCaught() {
86
return defaultExceptionCaught;
87
}
88
89
/**
90
* This flag will be set true if any event which does not have specific
91
* listener has been received.
92
*/
93
private static volatile boolean unexpectedEventCaught = false;
94
public static synchronized boolean unexpectedEventCaught() {
95
return unexpectedEventCaught;
96
}
97
98
/**
99
* This flag shows if debugged VM is connected to debugger.
100
*/
101
private static volatile boolean vmDisconnected = false;
102
public static synchronized boolean isDisconnected() {
103
return vmDisconnected;
104
}
105
106
public EventHandler(Debugee debuggee, Log log) {
107
this.listenThread = new Thread(this);
108
this.listenThread.setDaemon(true);
109
110
this.debuggee = debuggee;
111
this.log = log;
112
this.vm = debuggee.VM();
113
this.requestManager = vm.eventRequestManager();
114
}
115
116
private void display(String str) {
117
log.display("EventHandler> " + str);
118
}
119
120
// is EventHandler was interrupted
121
private volatile boolean wasInterrupted;
122
123
public void stopEventHandler() {
124
wasInterrupted = true;
125
126
listenThread.interrupt();
127
128
try {
129
listenThread.join();
130
}
131
catch(InterruptedException e) {
132
throw new TestBug("Unexpected exception: " + e);
133
}
134
}
135
/**
136
* The <code>EventHandler</code> thread keeps running until a VMDisconnectedEvent occurs
137
* or some exception occurs during event processing.
138
*/
139
public void run() {
140
synchronized(EventHandler.this) {
141
status = 1; // running
142
}
143
do {
144
try {
145
EventSet set = vm.eventQueue().remove();
146
147
switch (set.suspendPolicy()) {
148
case EventRequest.SUSPEND_NONE:
149
display("Received event set with policy = SUSPEND_NONE");
150
break;
151
case EventRequest.SUSPEND_ALL:
152
display("Received event set with policy = SUSPEND_ALL");
153
break;
154
case EventRequest.SUSPEND_EVENT_THREAD:
155
display("Received event set with policy = SUSPEND_EVENT_THREAD");
156
break;
157
}
158
159
synchronized (listeners) {
160
synchronized (EventHandler.this) {
161
for (EventListener listener : listeners) {
162
// proloque listener for a event set
163
listener.eventSetReceived(set);
164
}
165
166
for (Event event : set) {
167
// print only event class name here because of Event,toString may cause unexpected exception
168
display("Event: " + event.getClass().getSimpleName()
169
+ " req " + event.request());
170
boolean processed = false;
171
for (EventListener listener : listeners) {
172
processed = listener.eventReceived(event);
173
174
if (processed) {
175
if (listener.shouldRemoveListener()) {
176
listener.eventSetComplete(set);
177
removeListener(listener);
178
}
179
180
break;
181
}
182
}
183
}
184
185
for (EventListener listener : listeners) {
186
// epiloque listener for a event set
187
listener.eventSetComplete(set);
188
}
189
}
190
}
191
192
}
193
catch (Exception e) {
194
195
if(e instanceof InterruptedException) {
196
if(wasInterrupted)
197
break;
198
}
199
200
log.complain("Exception occured in eventHandler thread: " + e.getMessage());
201
e.printStackTrace(log.getOutStream());
202
synchronized(EventHandler.this) {
203
// This will make the waiters such as waitForVMDisconnect
204
// exit their wait loops.
205
vmDisconnected = true;
206
status = 2; // abnormal termination
207
EventHandler.this.notifyAll();
208
}
209
throw new Failure(e);
210
}
211
} while (!wasInterrupted && !isDisconnected());
212
213
if (unexpectedEventCaught || defaultExceptionCaught) {
214
synchronized(EventHandler.this) {
215
status = 2;
216
}
217
}
218
display("finished");
219
}
220
221
222
/**
223
* This is normally called in the main thread of the test debugger.
224
* It starts up an <code>EventHandler</code> thread that gets events coming in
225
* from the debuggee and distributes them to listeners.
226
*/
227
public void startListening() {
228
createDefaultEventRequests();
229
createDefaultListeners();
230
listenThread.start();
231
}
232
233
234
/**
235
* This method sets up default requests.
236
*/
237
private void createDefaultEventRequests() {
238
/**
239
* The following request will allow to print a warning if a debuggee gets an
240
* unexpected exception. The unexpected exception will be handled in
241
* the eventReceived method in the default listener created.
242
* If a test case does not want an uncaught exception to cause a
243
* message, it must add new listener for uncaught exception events to
244
* handle them.
245
*/
246
defaultExceptionRequest = requestManager.createExceptionRequest(null, false, true);
247
defaultExceptionRequest.enable();
248
}
249
250
/**
251
* This method sets up default listeners.
252
*/
253
private void createDefaultListeners() {
254
/**
255
* This listener catches up all unexpected events.
256
*
257
*/
258
addListener(
259
new EventListener() {
260
public boolean eventReceived(Event event) {
261
log.complain("EventHandler> Unexpected event: " + event.getClass().getName());
262
unexpectedEventCaught = true;
263
return true;
264
}
265
}
266
);
267
268
/**
269
* This listener catches up VMStart event.
270
*/
271
addListener(
272
new EventListener() {
273
public boolean eventReceived(Event event) {
274
if (event instanceof VMStartEvent) {
275
display("received VMStart");
276
removeListener(this);
277
return true;
278
}
279
return false;
280
}
281
}
282
);
283
284
/**
285
* This listener catches up VMDeath event.
286
*/
287
addListener(
288
new EventListener() {
289
public boolean eventReceived(Event event) {
290
if (event instanceof VMDeathEvent) {
291
display("receieved VMDeath");
292
removeListener(this);
293
return true;
294
}
295
return false;
296
}
297
}
298
);
299
300
/**
301
* This listener catches up <code>VMDisconnectEvent</code>event and
302
* signals <code>EventHandler</code> thread to finish.
303
*/
304
addListener(
305
new EventListener() {
306
public boolean eventReceived(Event event) {
307
if (event instanceof VMDisconnectEvent ) {
308
display("receieved VMDisconnect");
309
synchronized(EventHandler.this) {
310
vmDisconnected = true;
311
status = 0; // OK finish
312
EventHandler.this.notifyAll();
313
removeListener(this);
314
}
315
return true;
316
}
317
return false;
318
}
319
}
320
);
321
322
/**
323
* This listener catches uncaught exceptions and print a message.
324
*/
325
addListener( new EventListener() {
326
public boolean eventReceived(Event event) {
327
boolean handled = false;
328
329
if (event instanceof ExceptionEvent &&
330
defaultExceptionRequest != null &&
331
defaultExceptionRequest.equals(event.request())) {
332
333
if (EventFilters.filtered(event) == false) {
334
log.complain("EventHandler> Unexpected Debuggee Exception: " +
335
(ExceptionEvent)event);
336
defaultExceptionCaught = true;
337
}
338
339
handled = true;
340
vm.resume();
341
}
342
343
return handled;
344
}
345
}
346
);
347
}
348
349
/**
350
* Add at beginning of the list because we want
351
* the LAST added listener to be FIRST to process
352
* current event.
353
*/
354
public void addListener(EventListener listener) {
355
display("Adding listener " + listener);
356
synchronized(listeners) {
357
listeners.add(0, listener);
358
}
359
}
360
361
/**
362
* Removes the listener from the list.
363
*/
364
public void removeListener(EventListener listener) {
365
display("Removing listener " + listener);
366
synchronized(listeners) {
367
listeners.remove(listener);
368
}
369
}
370
371
372
/**
373
* Returns an event which is received for any of given requests.
374
*/
375
public Event waitForRequestedEvent( final EventRequest[] requests,
376
long timeout,
377
boolean shouldRemoveListeners) {
378
class EventNotification {
379
volatile Event event = null;
380
}
381
final EventNotification en = new EventNotification();
382
383
EventListener listener = new EventListener() {
384
public boolean eventReceived(Event event) {
385
for (int i = 0; i < requests.length; i++) {
386
EventRequest request = requests[i];
387
if (!request.isEnabled())
388
continue;
389
if (request.equals(event.request())) {
390
display("waitForRequestedEvent: Received event(" + event + ") for request(" + request + ")");
391
synchronized (EventHandler.this) {
392
en.event = event;
393
EventHandler.this.notifyAll();
394
}
395
return true;
396
}
397
}
398
return false;
399
}
400
};
401
if (shouldRemoveListeners) {
402
display("waitForRequestedEvent: enabling remove of listener " + listener);
403
listener.enableRemovingThisListener();
404
}
405
for (int i = 0; i < requests.length; i++) {
406
requests[i].enable();
407
}
408
addListener(listener);
409
410
try {
411
long timeToFinish = System.currentTimeMillis() + timeout;
412
long timeLeft = timeout;
413
synchronized (EventHandler.this) {
414
display("waitForRequestedEvent: vm.resume called");
415
vm.resume();
416
417
while (!isDisconnected() && en.event == null && timeLeft > 0) {
418
EventHandler.this.wait(timeLeft);
419
timeLeft = timeToFinish - System.currentTimeMillis();
420
}
421
}
422
} catch (InterruptedException e) {
423
return null;
424
}
425
if (shouldRemoveListeners && !isDisconnected()) {
426
for (int i = 0; i < requests.length; i++) {
427
requests[i].disable();
428
}
429
}
430
if (en.event == null) {
431
throw new Failure("waitForRequestedEvent: no requested events have been received.");
432
}
433
return en.event;
434
}
435
436
/**
437
* Returns an event set which is received for any of given requests.
438
*/
439
public EventSet waitForRequestedEventSet( final EventRequest[] requests,
440
long timeout,
441
boolean shouldRemoveListeners) {
442
class EventNotification {
443
volatile EventSet set = null;
444
}
445
final EventNotification en = new EventNotification();
446
447
EventListener listener = new EventListener() {
448
public void eventSetReceived(EventSet set) {
449
450
EventIterator eventIterator = set.eventIterator();
451
452
while (eventIterator.hasNext()) {
453
454
Event event = eventIterator.nextEvent();
455
456
for (int i = 0; i < requests.length; i++) {
457
EventRequest request = requests[i];
458
if (!request.isEnabled())
459
continue;
460
461
if (request.equals(event.request())) {
462
display("waitForRequestedEventSet: Received event set for request: " + request);
463
synchronized (EventHandler.this) {
464
en.set = set;
465
EventHandler.this.notifyAll();
466
}
467
return;
468
}
469
}
470
}
471
}
472
473
public boolean eventReceived(Event event) {
474
return (en.set != null);
475
}
476
};
477
478
if (shouldRemoveListeners) {
479
display("waitForRequestedEventSet: enabling remove of listener " + listener);
480
listener.enableRemovingThisListener();
481
}
482
for (int i = 0; i < requests.length; i++) {
483
requests[i].enable();
484
}
485
addListener(listener);
486
487
try {
488
long timeToFinish = System.currentTimeMillis() + timeout;
489
long timeLeft = timeout;
490
synchronized (EventHandler.this) {
491
display("waitForRequestedEventSet: vm.resume called");
492
vm.resume();
493
494
while (!isDisconnected() && en.set == null && timeLeft > 0) {
495
EventHandler.this.wait(timeLeft);
496
timeLeft = timeToFinish - System.currentTimeMillis();
497
}
498
}
499
} catch (InterruptedException e) {
500
return null;
501
}
502
if (shouldRemoveListeners && !isDisconnected()) {
503
for (int i = 0; i < requests.length; i++) {
504
requests[i].disable();
505
}
506
}
507
if (en.set == null) {
508
throw new Failure("waitForRequestedEventSet: no requested events have been received.");
509
}
510
return en.set;
511
}
512
513
public synchronized void waitForVMDisconnect() {
514
display("waitForVMDisconnect");
515
while (!isDisconnected()) {
516
try {
517
wait();
518
} catch (InterruptedException e) {
519
}
520
}
521
display("waitForVMDisconnect: done");
522
}
523
524
/**
525
* This is a superclass for any event listener.
526
*/
527
public static class EventListener {
528
529
/**
530
* This flag shows if the listener must be removed
531
* after current event has been processed by
532
* this listener.
533
*/
534
volatile boolean shouldRemoveListener = false;
535
public boolean shouldRemoveListener() {
536
return shouldRemoveListener;
537
}
538
539
public void enableRemovingThisListener() {
540
shouldRemoveListener = true;
541
}
542
543
/**
544
* This method will be called by <code>EventHandler</code>
545
* for received event set before any call of <code>eventReceived</code>
546
* method for events contained in this set.
547
*/
548
public void eventSetReceived(EventSet set) {}
549
550
551
/**
552
* This method will be called by <code>EventHandler</code>
553
* for received event set after all calls of <code>eventReceived</code>
554
* and event specific methods for all events contained in this set.
555
*/
556
public void eventSetComplete(EventSet set) {}
557
558
/**
559
* This method will be called by <code>EventHandler</code>
560
* for any event contained in received event set.
561
*
562
* @return <code>true</code> if event was processed by this
563
* <code>EventListener<code> or <code>false</code> otherwise.
564
*/
565
public boolean eventReceived(Event event) {
566
return false;
567
}
568
}
569
}
570
571