Path: blob/master/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventQueueImpl.java
41161 views
/*1* Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.tools.jdi;2627import java.util.LinkedList;2829import com.sun.jdi.VMDisconnectedException;30import com.sun.jdi.VirtualMachine;31import com.sun.jdi.event.EventQueue;32import com.sun.jdi.event.EventSet;3334public class EventQueueImpl extends MirrorImpl implements EventQueue {3536/*37* Note this is not a synchronized list. Iteration/update should be38* protected through the 'this' monitor.39*/40LinkedList<EventSet> eventSets = new LinkedList<>();4142TargetVM target;43boolean closed = false;4445EventQueueImpl(VirtualMachine vm, TargetVM target) {46super(vm);47this.target = target;48target.addEventQueue(this);49}5051/*52* Override superclass back to default equality53*/54public boolean equals(Object obj) {55return this == obj;56}5758public int hashCode() {59return System.identityHashCode(this);60}6162synchronized void enqueue(EventSet eventSet) {63eventSets.add(eventSet);64notifyAll();65}6667synchronized int size() {68return eventSets.size();69}7071synchronized void close() {72if (!closed) {73closed = true; // OK for this the be first since synchronized7475// place VMDisconnectEvent into queue76enqueue(new EventSetImpl(vm,77(byte)JDWP.EventKind.VM_DISCONNECTED));78}79}8081public EventSet remove() throws InterruptedException {82return remove(0);83}8485/**86* Filter out events not for user's eyes.87* Then filter out empty sets.88*/89public EventSet remove(long timeout) throws InterruptedException {90if (timeout < 0) {91throw new IllegalArgumentException("Timeout cannot be negative");92}9394EventSet eventSet;95while (true) {96EventSetImpl fullEventSet = removeUnfiltered(timeout);97if (fullEventSet == null) {98eventSet = null; // timeout99break;100}101/*102* Remove events from the event set for which103* there is no corresponding enabled request (104* this includes our internally requested events.)105* This never returns null106*/107eventSet = fullEventSet.userFilter();108if (!eventSet.isEmpty()) {109break;110}111}112113if ((eventSet != null) && (eventSet.suspendPolicy() == JDWP.SuspendPolicy.ALL)) {114vm.notifySuspend();115}116117return eventSet;118}119120EventSet removeInternal() throws InterruptedException {121EventSet eventSet;122do {123// Waiting forever, so removeUnfiltered() is never null124eventSet = removeUnfiltered(0).internalFilter();125} while (eventSet == null || eventSet.isEmpty());126127/*128* Currently, no internal events are requested with a suspend129* policy other than none, so we don't check for notifySuspend()130* here. If this changes in the future, there is much131* infrastructure that needs to be updated.132*/133134return eventSet;135}136137private TimerThread startTimerThread(long timeout) {138TimerThread thread = new TimerThread(timeout);139thread.setDaemon(true);140thread.start();141return thread;142}143144private boolean shouldWait(TimerThread timerThread) {145return !closed && eventSets.isEmpty() &&146((timerThread == null) ? true : !timerThread.timedOut());147}148149private EventSetImpl removeUnfiltered(long timeout)150throws InterruptedException {151EventSetImpl eventSet = null;152153/*154* Make sure the VM has completed initialization before155* trying to build events.156*/157vm.waitInitCompletion();158159synchronized(this) {160if (!eventSets.isEmpty()) {161/*162* If there's already something there, no need163* for anything elaborate.164*/165eventSet = (EventSetImpl)eventSets.removeFirst();166} else {167/*168* If a timeout was specified, create a thread to169* notify this one when a timeout170* occurs. We can't use the timed version of wait()171* because it is possible for multiple enqueue() calls172* before we see something in the eventSet queue173* (this is possible when multiple threads call174* remove() concurrently -- not a great idea, but175* it should be supported). Even if enqueue() did a176* notify() instead of notifyAll() we are not able to177* use a timed wait because there's no way to distinguish178* a timeout from a notify. That limitation implies a179* possible race condition between a timed out thread180* and a notified thread.181*/182TimerThread timerThread = null;183try {184if (timeout > 0) {185timerThread = startTimerThread(timeout);186}187188while (shouldWait(timerThread)) {189this.wait();190}191} finally {192if ((timerThread != null) && !timerThread.timedOut()) {193timerThread.interrupt();194}195}196197if (eventSets.isEmpty()) {198if (closed) {199throw new VMDisconnectedException();200}201} else {202eventSet = (EventSetImpl)eventSets.removeFirst();203}204}205}206207// The build is synchronized on the event set, don't hold208// the queue lock.209if (eventSet != null) {210target.notifyDequeueEventSet();211eventSet.build();212}213return eventSet;214}215216private class TimerThread extends Thread {217private boolean timedOut = false;218private long timeout;219220TimerThread(long timeout) {221super(vm.threadGroupForJDI(), "JDI Event Queue Timer");222this.timeout = timeout;223}224225boolean timedOut() {226return timedOut;227}228229public void run() {230try {231Thread.sleep(timeout);232EventQueueImpl queue = EventQueueImpl.this;233synchronized(queue) {234timedOut = true;235queue.notifyAll();236}237} catch (InterruptedException e) {238// Exit without notifying239}240}241}242}243244245