jdk/src/share/classes/com/sun/tools/jdi/EventQueueImpl.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1998-2006 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package com.sun.tools.jdi;
       
    27 
       
    28 import com.sun.jdi.*;
       
    29 import com.sun.jdi.event.EventQueue;
       
    30 import com.sun.jdi.event.EventSet;
       
    31 
       
    32 import java.util.*;
       
    33 
       
    34 public class EventQueueImpl extends MirrorImpl implements EventQueue {
       
    35 
       
    36     /*
       
    37      * Note this is not a synchronized list. Iteration/update should be
       
    38      * protected through the 'this' monitor.
       
    39      */
       
    40     LinkedList<EventSet> eventSets = new LinkedList<EventSet>();
       
    41 
       
    42     TargetVM target;
       
    43     boolean closed = false;
       
    44 
       
    45     EventQueueImpl(VirtualMachine vm, TargetVM target) {
       
    46         super(vm);
       
    47         this.target = target;
       
    48         target.addEventQueue(this);
       
    49     }
       
    50 
       
    51     /*
       
    52      * Override superclass back to default equality
       
    53      */
       
    54     public boolean equals(Object obj) {
       
    55         return this == obj;
       
    56     }
       
    57 
       
    58     public int hashCode() {
       
    59         return System.identityHashCode(this);
       
    60     }
       
    61 
       
    62     synchronized void enqueue(EventSet eventSet) {
       
    63         eventSets.add(eventSet);
       
    64         notifyAll();
       
    65     }
       
    66 
       
    67     synchronized int size() {
       
    68         return eventSets.size();
       
    69     }
       
    70 
       
    71     synchronized void close() {
       
    72         if (!closed) {
       
    73             closed = true; // OK for this the be first since synchronized
       
    74 
       
    75             // place VMDisconnectEvent into queue
       
    76             enqueue(new EventSetImpl(vm,
       
    77                                      (byte)JDWP.EventKind.VM_DISCONNECTED));
       
    78         }
       
    79     }
       
    80 
       
    81     public EventSet remove() throws InterruptedException {
       
    82         return remove(0);
       
    83     }
       
    84 
       
    85     /**
       
    86      * Filter out events not for user's eyes.
       
    87      * Then filter out empty sets.
       
    88      */
       
    89     public EventSet remove(long timeout) throws InterruptedException {
       
    90         if (timeout < 0) {
       
    91             throw new IllegalArgumentException("Timeout cannot be negative");
       
    92         }
       
    93 
       
    94         EventSet eventSet;
       
    95         while (true) {
       
    96             EventSetImpl fullEventSet = removeUnfiltered(timeout);
       
    97             if (fullEventSet == null) {
       
    98                 eventSet = null;  // timeout
       
    99                 break;
       
   100             }
       
   101             /*
       
   102              * Remove events from the event set for which
       
   103              * there is no corresponding enabled request (
       
   104              * this includes our internally requested events.)
       
   105              * This never returns null
       
   106              */
       
   107             eventSet = fullEventSet.userFilter();
       
   108             if (!eventSet.isEmpty()) {
       
   109                 break;
       
   110             }
       
   111         }
       
   112 
       
   113         if ((eventSet != null) && (eventSet.suspendPolicy() == JDWP.SuspendPolicy.ALL)) {
       
   114             vm.notifySuspend();
       
   115         }
       
   116 
       
   117         return eventSet;
       
   118     }
       
   119 
       
   120     EventSet removeInternal() throws InterruptedException {
       
   121         EventSet eventSet;
       
   122         do {
       
   123             // Waiting forever, so removeUnfiltered() is never null
       
   124             eventSet = removeUnfiltered(0).internalFilter();
       
   125         } while (eventSet == null || eventSet.isEmpty());
       
   126 
       
   127         /*
       
   128          * Currently, no internal events are requested with a suspend
       
   129          * policy other than none, so we don't check for notifySuspend()
       
   130          * here. If this changes in the future, there is much
       
   131          * infrastructure that needs to be updated.
       
   132          */
       
   133 
       
   134         return eventSet;
       
   135     }
       
   136 
       
   137     private TimerThread startTimerThread(long timeout) {
       
   138         TimerThread thread = new TimerThread(timeout);
       
   139         thread.setDaemon(true);
       
   140         thread.start();
       
   141         return thread;
       
   142     }
       
   143 
       
   144     private boolean shouldWait(TimerThread timerThread) {
       
   145         return !closed && eventSets.isEmpty() &&
       
   146                ((timerThread == null) ? true : !timerThread.timedOut());
       
   147     }
       
   148 
       
   149     private EventSetImpl removeUnfiltered(long timeout)
       
   150                                                throws InterruptedException {
       
   151         EventSetImpl eventSet = null;
       
   152 
       
   153         /*
       
   154          * Make sure the VM has completed initialization before
       
   155          * trying to build events.
       
   156          */
       
   157         vm.waitInitCompletion();
       
   158 
       
   159         synchronized(this) {
       
   160             if (!eventSets.isEmpty()) {
       
   161                 /*
       
   162                  * If there's already something there, no need
       
   163                  * for anything elaborate.
       
   164                  */
       
   165                 eventSet = (EventSetImpl)eventSets.removeFirst();
       
   166             } else {
       
   167                 /*
       
   168                  * If a timeout was specified, create a thread to
       
   169                  * notify this one when a timeout
       
   170                  * occurs. We can't use the timed version of wait()
       
   171                  * because it is possible for multiple enqueue() calls
       
   172                  * before we see something in the eventSet queue
       
   173                  * (this is possible when multiple threads call
       
   174                  * remove() concurrently -- not a great idea, but
       
   175                  * it should be supported). Even if enqueue() did a
       
   176                  * notify() instead of notifyAll() we are not able to
       
   177                  * use a timed wait because there's no way to distinguish
       
   178                  * a timeout from a notify.  That limitation implies a
       
   179                  * possible race condition between a timed out thread
       
   180                  * and a notified thread.
       
   181                  */
       
   182                 TimerThread timerThread = null;
       
   183                 try {
       
   184                     if (timeout > 0) {
       
   185                         timerThread = startTimerThread(timeout);
       
   186                     }
       
   187 
       
   188                     while (shouldWait(timerThread)) {
       
   189                         this.wait();
       
   190                     }
       
   191                 } finally {
       
   192                     if ((timerThread != null) && !timerThread.timedOut()) {
       
   193                         timerThread.interrupt();
       
   194                     }
       
   195                 }
       
   196 
       
   197                 if (eventSets.isEmpty()) {
       
   198                     if (closed) {
       
   199                         throw new VMDisconnectedException();
       
   200                     }
       
   201                 } else {
       
   202                     eventSet = (EventSetImpl)eventSets.removeFirst();
       
   203                 }
       
   204             }
       
   205         }
       
   206 
       
   207         // The build is synchronized on the event set, don't hold
       
   208         // the queue lock.
       
   209         if (eventSet != null) {
       
   210             target.notifyDequeueEventSet();
       
   211             eventSet.build();
       
   212         }
       
   213         return eventSet;
       
   214     }
       
   215 
       
   216     private class TimerThread extends Thread {
       
   217         private boolean timedOut = false;
       
   218         private long timeout;
       
   219 
       
   220         TimerThread(long timeout) {
       
   221             super(vm.threadGroupForJDI(), "JDI Event Queue Timer");
       
   222             this.timeout = timeout;
       
   223         }
       
   224 
       
   225         boolean timedOut() {
       
   226             return timedOut;
       
   227         }
       
   228 
       
   229         public void run() {
       
   230             try {
       
   231                 Thread.sleep(timeout);
       
   232                 EventQueueImpl queue = EventQueueImpl.this;
       
   233                 synchronized(queue) {
       
   234                     timedOut = true;
       
   235                     queue.notifyAll();
       
   236                 }
       
   237             } catch (InterruptedException e) {
       
   238                 // Exit without notifying
       
   239             }
       
   240         }
       
   241     }
       
   242 }