jdk/src/share/classes/com/sun/tools/jdi/VMState.java
changeset 2 90ce3da70b43
child 836 d81b1f62fb82
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1999 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 
       
    30 import java.lang.ref.WeakReference;
       
    31 import java.util.*;
       
    32 
       
    33 class VMState {
       
    34     private final VirtualMachineImpl vm;
       
    35 
       
    36     // Listeners
       
    37     private final List<WeakReference> listeners = new ArrayList<WeakReference>(); // synchronized (this)
       
    38     private boolean notifyingListeners = false;  // synchronized (this)
       
    39 
       
    40     /*
       
    41      * Certain information can be cached only when the entire VM is
       
    42      * suspended and there are no pending resumes. The fields below
       
    43      * are used to track whether there are pending resumes. (There
       
    44      * is an assumption that JDWP command ids are increasing over time.)
       
    45      */
       
    46     private int lastCompletedCommandId = 0;   // synchronized (this)
       
    47     private int lastResumeCommandId = 0;      // synchronized (this)
       
    48 
       
    49     // This is cached only while the VM is suspended
       
    50     private static class Cache {
       
    51         List<ThreadGroupReference> groups = null;  // cached Top Level ThreadGroups
       
    52         List<ThreadReference> threads = null; // cached Threads
       
    53     }
       
    54 
       
    55     private Cache cache = null;               // synchronized (this)
       
    56     private static final Cache markerCache = new Cache();
       
    57 
       
    58     private void disableCache() {
       
    59         synchronized (this) {
       
    60             cache = null;
       
    61         }
       
    62     }
       
    63 
       
    64     private void enableCache() {
       
    65         synchronized (this) {
       
    66             cache = markerCache;
       
    67         }
       
    68     }
       
    69 
       
    70     private Cache getCache() {
       
    71         synchronized (this) {
       
    72             if (cache == markerCache) {
       
    73                 cache = new Cache();
       
    74             }
       
    75             return cache;
       
    76         }
       
    77     }
       
    78 
       
    79     VMState(VirtualMachineImpl vm) {
       
    80         this.vm = vm;
       
    81     }
       
    82 
       
    83     /**
       
    84      * Is the VM currently suspended, for the purpose of caching?
       
    85      * Must be called synchronized on vm.state()
       
    86      */
       
    87     boolean isSuspended() {
       
    88         return cache != null;
       
    89     }
       
    90 
       
    91     /*
       
    92      * A JDWP command has been completed (reply has been received).
       
    93      * Update data that tracks pending resume commands.
       
    94      */
       
    95     synchronized void notifyCommandComplete(int id) {
       
    96         lastCompletedCommandId = id;
       
    97     }
       
    98 
       
    99     synchronized void freeze() {
       
   100         if (cache == null && (lastCompletedCommandId >= lastResumeCommandId)) {
       
   101             /*
       
   102              * No pending resumes to worry about. The VM is suspended
       
   103              * and additional state can be cached. Notify all
       
   104              * interested listeners.
       
   105              */
       
   106             processVMAction(new VMAction(vm, VMAction.VM_SUSPENDED));
       
   107             enableCache();
       
   108         }
       
   109     }
       
   110 
       
   111     synchronized PacketStream thawCommand(CommandSender sender) {
       
   112         PacketStream stream = sender.send();
       
   113         lastResumeCommandId = stream.id();
       
   114         thaw();
       
   115         return stream;
       
   116     }
       
   117 
       
   118     /**
       
   119      * Tell listeners to invalidate suspend-sensitive caches.
       
   120      */
       
   121     synchronized void thaw() {
       
   122         if (cache != null) {
       
   123             if ((vm.traceFlags & vm.TRACE_OBJREFS) != 0) {
       
   124                 vm.printTrace("Clearing VM suspended cache");
       
   125             }
       
   126             disableCache();
       
   127         }
       
   128         processVMAction(new VMAction(vm, VMAction.VM_NOT_SUSPENDED));
       
   129     }
       
   130 
       
   131     private synchronized void processVMAction(VMAction action) {
       
   132         if (!notifyingListeners) {
       
   133             // Prevent recursion
       
   134             notifyingListeners = true;
       
   135 
       
   136             Iterator iter = listeners.iterator();
       
   137             while (iter.hasNext()) {
       
   138                 WeakReference ref = (WeakReference)iter.next();
       
   139                 VMListener listener = (VMListener)ref.get();
       
   140                 if (listener != null) {
       
   141                     boolean keep = true;
       
   142                     switch (action.id()) {
       
   143                         case VMAction.VM_SUSPENDED:
       
   144                             keep = listener.vmSuspended(action);
       
   145                             break;
       
   146                         case VMAction.VM_NOT_SUSPENDED:
       
   147                             keep = listener.vmNotSuspended(action);
       
   148                             break;
       
   149                     }
       
   150                     if (!keep) {
       
   151                         iter.remove();
       
   152                     }
       
   153                 } else {
       
   154                     // Listener is unreachable; clean up
       
   155                     iter.remove();
       
   156                 }
       
   157             }
       
   158 
       
   159             notifyingListeners = false;
       
   160         }
       
   161     }
       
   162 
       
   163     synchronized void addListener(VMListener listener) {
       
   164         listeners.add(new WeakReference<VMListener>(listener));
       
   165     }
       
   166 
       
   167     synchronized boolean hasListener(VMListener listener) {
       
   168         return listeners.contains(listener);
       
   169     }
       
   170 
       
   171     synchronized void removeListener(VMListener listener) {
       
   172         Iterator iter = listeners.iterator();
       
   173         while (iter.hasNext()) {
       
   174             WeakReference ref = (WeakReference)iter.next();
       
   175             if (listener.equals(ref.get())) {
       
   176                 iter.remove();
       
   177                 break;
       
   178             }
       
   179         }
       
   180     }
       
   181 
       
   182     List<ThreadReference> allThreads() {
       
   183         List<ThreadReference> threads = null;
       
   184         try {
       
   185             Cache local = getCache();
       
   186 
       
   187             if (local != null) {
       
   188                 // may be stale when returned, but not provably so
       
   189                 threads = local.threads;
       
   190             }
       
   191             if (threads == null) {
       
   192                 threads = Arrays.asList((ThreadReference[])JDWP.VirtualMachine.AllThreads.
       
   193                                         process(vm).threads);
       
   194                 if (local != null) {
       
   195                     local.threads = threads;
       
   196                     if ((vm.traceFlags & vm.TRACE_OBJREFS) != 0) {
       
   197                         vm.printTrace("Caching all threads (count = " +
       
   198                                       threads.size() + ") while VM suspended");
       
   199                     }
       
   200                 }
       
   201             }
       
   202         } catch (JDWPException exc) {
       
   203             throw exc.toJDIException();
       
   204         }
       
   205         return threads;
       
   206     }
       
   207 
       
   208 
       
   209     List<ThreadGroupReference> topLevelThreadGroups() {
       
   210         List<ThreadGroupReference> groups = null;
       
   211         try {
       
   212             Cache local = getCache();
       
   213 
       
   214             if (local != null) {
       
   215                 groups = local.groups;
       
   216             }
       
   217             if (groups == null) {
       
   218                 groups = Arrays.asList(
       
   219                                 (ThreadGroupReference[])JDWP.VirtualMachine.TopLevelThreadGroups.
       
   220                                        process(vm).groups);
       
   221                 if (local != null) {
       
   222                     local.groups = groups;
       
   223                     if ((vm.traceFlags & vm.TRACE_OBJREFS) != 0) {
       
   224                         vm.printTrace(
       
   225                           "Caching top level thread groups (count = " +
       
   226                           groups.size() + ") while VM suspended");
       
   227                     }
       
   228                 }
       
   229             }
       
   230         } catch (JDWPException exc) {
       
   231             throw exc.toJDIException();
       
   232         }
       
   233         return groups;
       
   234     }
       
   235 
       
   236 }