Source for gnu.classpath.jdwp.Jdwp

   1: /* Jdwp.java -- Virtual machine to JDWP back-end programming interface
   2:    Copyright (C) 2005 Free Software Foundation
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: terms of your choice, provided that you also meet, for each linked
  32: independent module, the terms and conditions of the license of that
  33: module.  An independent module is a module which is not derived from
  34: or based on this library.  If you modify this library, you may extend
  35: this exception to your version of the library, but you are not
  36: obligated to do so.  If you do not wish to do so, delete this
  37: exception statement from your version. */
  38: 
  39: 
  40: package gnu.classpath.jdwp;
  41: 
  42: import gnu.classpath.jdwp.event.Event;
  43: import gnu.classpath.jdwp.event.EventManager;
  44: import gnu.classpath.jdwp.event.EventRequest;
  45: import gnu.classpath.jdwp.id.ThreadId;
  46: import gnu.classpath.jdwp.processor.PacketProcessor;
  47: import gnu.classpath.jdwp.transport.ITransport;
  48: import gnu.classpath.jdwp.transport.JdwpConnection;
  49: import gnu.classpath.jdwp.transport.TransportException;
  50: import gnu.classpath.jdwp.transport.TransportFactory;
  51: 
  52: import java.io.IOException;
  53: import java.security.AccessController;
  54: import java.util.HashMap;
  55: 
  56: /**
  57:  * Main interface from the virtual machine to the JDWP back-end.
  58:  *
  59:  * @author Keith Seitz (keiths@redhat.com)
  60:  */
  61: public class Jdwp
  62:   extends Thread
  63: {
  64:   // The single instance of the back-end
  65:   private static Jdwp _instance = null;
  66: 
  67:   /**
  68:    * Are we debugging?
  69:    */
  70:   public static boolean isDebugging = false;
  71: 
  72:   // Packet processor
  73:   private PacketProcessor _packetProcessor;
  74:   private Thread _ppThread;
  75: 
  76:   // JDWP configuration properties
  77:   private HashMap _properties;
  78: 
  79:   // The suspend property of the configure string
  80:   // (-Xrunjdwp:..suspend=<boolean>)
  81:   private static final String _PROPERTY_SUSPEND = "suspend";
  82: 
  83:   // User's main application thread
  84:   private Thread _mainThread;
  85: 
  86:   // Connection to debugger
  87:   private JdwpConnection _connection;
  88: 
  89:   // Are we shutting down the current session?
  90:   private boolean _shutdown;
  91: 
  92:   // A thread group for the JDWP threads
  93:   private ThreadGroup _group;
  94: 
  95:   /**
  96:    * constructor
  97:    */
  98:   public Jdwp ()
  99:   {
 100:     _shutdown = false;
 101:     isDebugging = true;
 102:     _instance = this;
 103:   }
 104: 
 105:   /**
 106:    * Returns the JDWP back-end, creating an instance of it
 107:    * if one does not already exist.
 108:    */
 109:   public static Jdwp getDefault ()
 110:   {
 111:     return _instance;
 112:   }
 113: 
 114:   /**
 115:    * Should the virtual machine suspend on startup?
 116:    */
 117:   public static boolean suspendOnStartup ()
 118:   {
 119:     Jdwp jdwp = getDefault ();
 120:     if (jdwp != null)
 121:       {
 122:     String suspend = (String) jdwp._properties.get (_PROPERTY_SUSPEND);
 123:     if (suspend != null && suspend.equals ("y"))
 124:       return true;
 125:       }
 126: 
 127:     return false;
 128:   }
 129: 
 130:   /**
 131:    * Configures the back-end
 132:    *
 133:    * @param configArgs  a string of configury options
 134:    * @param mainThread  the main application thread
 135:    */
 136:   public void configure (String configArgs, Thread mainThread)
 137:   {
 138:     _mainThread = mainThread;
 139:     _processConfigury (configArgs);
 140:   }
 141: 
 142:   // A helper function to initialize the transport layer
 143:   private void _doInitialization ()
 144:     throws TransportException
 145:   {
 146:     _group = new ThreadGroup ("JDWP threads");
 147:     // initialize transport
 148:     ITransport transport = TransportFactory.newInstance (_properties);
 149:     _connection = new JdwpConnection (_group, transport);
 150:     _connection.initialize ();
 151:     _connection.start ();
 152: 
 153:     // Create processor
 154:     _packetProcessor = new PacketProcessor (_connection);
 155:     _ppThread = new Thread (_group, new Runnable ()
 156:       {
 157:     public void run ()
 158:     {
 159:       AccessController.doPrivileged (_packetProcessor);
 160:     }
 161:       });
 162:     _ppThread.start ();
 163:   }
 164: 
 165:   /**
 166:    * Shutdown the JDWP back-end
 167:    *
 168:    * NOTE: This does not quite work properly. See notes in 
 169:    * run() on this subject (catch of InterruptedException).
 170:    */
 171:   public void shutdown ()
 172:   {
 173:     if (!_shutdown)
 174:       {
 175:     _packetProcessor.shutdown ();
 176:     _ppThread.interrupt ();
 177:     _connection.shutdown ();
 178:     _shutdown = true;
 179:     isDebugging = false;
 180: 
 181:     /* FIXME: probably need to check state of user's
 182:        program -- if it is suspended, we need to either
 183:        resume or kill them. */
 184: 
 185:     interrupt ();
 186:       }
 187:   }
 188: 
 189:   /**
 190:    * Notify the debugger of an event. This method should not
 191:    * be called if debugging is not active (but it would not
 192:    * cause any harm). Places where event notifications occur
 193:    * should check isDebugging before doing anything.
 194:    *
 195:    * The event is filtered through the event manager before being
 196:    * sent.
 197:    *
 198:    * FIXME: Probably need logic to send multiple events
 199:    * @param event the event to report
 200:    */
 201:   public static void notify (Event event)
 202:   {
 203:     Jdwp jdwp = getDefault ();
 204:     if (jdwp != null)
 205:       {
 206:     EventManager em = EventManager.getDefault ();
 207:     EventRequest request = em.getEventRequest (event);
 208:     if (request != null)
 209:       sendEvent (request, event);
 210:       }
 211:   }
 212:   
 213:   /**
 214:    * Sends the event to the debugger.
 215:    *
 216:    * This method bypasses the event manager's filtering.
 217:    *
 218:    * @param  request  the debugger request for the event
 219:    * @param  event    the event to send
 220:    */
 221:   public static void sendEvent (EventRequest request, Event event)
 222:   {
 223:     Jdwp jdwp = getDefault ();
 224:     if (jdwp != null)
 225:       {
 226:     try
 227:       {
 228:         // !! May need to implement send queue?
 229:         synchronized (jdwp._connection)
 230:           {
 231:         jdwp._connection.sendEvent (request, event);
 232:           }
 233:         
 234:         // Follow suspend policy
 235:         jdwp._enforceSuspendPolicy (request.getSuspendPolicy ());
 236:       }
 237:     catch (IOException ie)
 238:       {
 239:         System.out.println ("Jdwp.notify: caught exception: " + ie);
 240:       }
 241:       }
 242:   }
 243: 
 244:   // Helper function to enforce suspend policies on event notification
 245:   private void _enforceSuspendPolicy (byte suspendPolicy)
 246:   {
 247:     switch (suspendPolicy)
 248:       {
 249:       case EventRequest.SUSPEND_NONE:
 250:     // do nothing
 251:     break;
 252: 
 253:       case EventRequest.SUSPEND_THREAD:
 254:     VMVirtualMachine.suspendThread (this);
 255:     break;
 256: 
 257:       case EventRequest.SUSPEND_ALL:
 258:     VMVirtualMachine.suspendAllThreads ();
 259:     break;
 260:       }
 261:   }
 262: 
 263:   public void run ()
 264:   {
 265:     try
 266:       {
 267:     _doInitialization ();
 268: 
 269:     _mainThread.start ();
 270: 
 271:     _mainThread.join ();
 272:       }
 273:     catch (InterruptedException ie)
 274:       {
 275:     /* Shutting down. If we're in server mode, we should
 276:        prepare for a new connection. Otherwise, we should
 277:        simply exit. */
 278:     // FIXME
 279:       }
 280:     catch (Throwable t)
 281:       {
 282:     System.out.println ("Exception in JDWP back-end: " + t);
 283:     System.exit (1);
 284:       }
 285:   }
 286: 
 287:   // A helper function to process the configure string "-Xrunjdwp:..."
 288:   private void _processConfigury (String configString)
 289:   {
 290:     // Loop through configuration arguments looking for a
 291:     // transport name
 292:     _properties = new HashMap ();
 293:     String[] options = configString.split (",");
 294:     for (int i = 0; i < options.length; ++i)
 295:       {
 296:     String[] property = options[i].split ("=");
 297:     if (property.length == 2)
 298:       _properties.put (property[0], property[1]);
 299:     // ignore malformed options
 300:       }
 301:   }
 302: }