242 lines · 7.8 KB · Java
RawDownload
/* * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.jdi; import com.sun.jdi.*;import com.sun.jdi.event.EventQueue;import com.sun.jdi.event.EventSet; import java.util.*; public class EventQueueImpl extends MirrorImpl implements EventQueue {     /*     * Note this is not a synchronized list. Iteration/update should be     * protected through the 'this' monitor.     */    LinkedList<EventSet> eventSets = new LinkedList<EventSet>();     TargetVM target;    boolean closed = false;     EventQueueImpl(VirtualMachine vm, TargetVM target) {        super(vm);        this.target = target;        target.addEventQueue(this);    }     /*     * Override superclass back to default equality     */    public boolean equals(Object obj) {        return this == obj;    }     public int hashCode() {        return System.identityHashCode(this);    }     synchronized void enqueue(EventSet eventSet) {        eventSets.add(eventSet);        notifyAll();    }     synchronized int size() {        return eventSets.size();    }     synchronized void close() {        if (!closed) {            closed = true; // OK for this the be first since synchronized             // place VMDisconnectEvent into queue            enqueue(new EventSetImpl(vm,                                     (byte)JDWP.EventKind.VM_DISCONNECTED));        }    }     public EventSet remove() throws InterruptedException {        return remove(0);    }     /**     * Filter out events not for user's eyes.     * Then filter out empty sets.     */    public EventSet remove(long timeout) throws InterruptedException {        if (timeout < 0) {            throw new IllegalArgumentException("Timeout cannot be negative");        }         EventSet eventSet;        while (true) {            EventSetImpl fullEventSet = removeUnfiltered(timeout);            if (fullEventSet == null) {                eventSet = null;  // timeout                break;            }            /*             * Remove events from the event set for which             * there is no corresponding enabled request (             * this includes our internally requested events.)             * This never returns null             */            eventSet = fullEventSet.userFilter();            if (!eventSet.isEmpty()) {                break;            }        }         if ((eventSet != null) && (eventSet.suspendPolicy() == JDWP.SuspendPolicy.ALL)) {            vm.notifySuspend();        }         return eventSet;    }     EventSet removeInternal() throws InterruptedException {        EventSet eventSet;        do {            // Waiting forever, so removeUnfiltered() is never null            eventSet = removeUnfiltered(0).internalFilter();        } while (eventSet == null || eventSet.isEmpty());         /*         * Currently, no internal events are requested with a suspend         * policy other than none, so we don't check for notifySuspend()         * here. If this changes in the future, there is much         * infrastructure that needs to be updated.         */         return eventSet;    }     private TimerThread startTimerThread(long timeout) {        TimerThread thread = new TimerThread(timeout);        thread.setDaemon(true);        thread.start();        return thread;    }     private boolean shouldWait(TimerThread timerThread) {        return !closed && eventSets.isEmpty() &&               ((timerThread == null) ? true : !timerThread.timedOut());    }     private EventSetImpl removeUnfiltered(long timeout)                                               throws InterruptedException {        EventSetImpl eventSet = null;         /*         * Make sure the VM has completed initialization before         * trying to build events.         */        vm.waitInitCompletion();         synchronized(this) {            if (!eventSets.isEmpty()) {                /*                 * If there's already something there, no need                 * for anything elaborate.                 */                eventSet = (EventSetImpl)eventSets.removeFirst();            } else {                /*                 * If a timeout was specified, create a thread to                 * notify this one when a timeout                 * occurs. We can't use the timed version of wait()                 * because it is possible for multiple enqueue() calls                 * before we see something in the eventSet queue                 * (this is possible when multiple threads call                 * remove() concurrently -- not a great idea, but                 * it should be supported). Even if enqueue() did a                 * notify() instead of notifyAll() we are not able to                 * use a timed wait because there's no way to distinguish                 * a timeout from a notify.  That limitation implies a                 * possible race condition between a timed out thread                 * and a notified thread.                 */                TimerThread timerThread = null;                try {                    if (timeout > 0) {                        timerThread = startTimerThread(timeout);                    }                     while (shouldWait(timerThread)) {                        this.wait();                    }                } finally {                    if ((timerThread != null) && !timerThread.timedOut()) {                        timerThread.interrupt();                    }                }                 if (eventSets.isEmpty()) {                    if (closed) {                        throw new VMDisconnectedException();                    }                } else {                    eventSet = (EventSetImpl)eventSets.removeFirst();                }            }        }         // The build is synchronized on the event set, don't hold        // the queue lock.        if (eventSet != null) {            target.notifyDequeueEventSet();            eventSet.build();        }        return eventSet;    }     private class TimerThread extends Thread {        private boolean timedOut = false;        private long timeout;         TimerThread(long timeout) {            super(vm.threadGroupForJDI(), "JDI Event Queue Timer");            this.timeout = timeout;        }         boolean timedOut() {            return timedOut;        }         public void run() {            try {                Thread.sleep(timeout);                EventQueueImpl queue = EventQueueImpl.this;                synchronized(queue) {                    timedOut = true;                    queue.notifyAll();                }            } catch (InterruptedException e) {                // Exit without notifying            }        }    }}