This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA/JDWP] JdwpConnection


Hi,

This is the final class for jdwp.transport. This is where it all comes
together.

I would appreciate more eyes on the threading issues. I think I have it
right, but I could be wrong. (I don't believe I'll ever feel confident
about threading issues. Too darn sneaky!)

A note about threads in this class: this class is a thread which reads
bytes off the transport, packages them into JdwpPackets, and adds the to
a packet queue for the packet processor thread(s) to grab. So other
threads will be accessing several (but not all) methods in this class
(like getPacket, sendPacket, shutdown).

I was originally planning to overlook shutdown because the JDWP spec is
not particularly clear about shutdown. It seems that once a debugger is
attached, the only way for the debugger to disconnect is via
VirtualMachine.Exit (in "normal" situations). The spec for this command
says that the VM be "abruptly" shut down. I believe this means via
System.exit -- the whole thing (VM & back-end) dies.

FWIW, I've spent a little time on clean shutdown for the case where the
debugger just closes its connection. This could then allow the JDWP
back-end to disconnect and allow the VM to continue executing bytecode.
[Of course, we could then also allow the possibility of re-attaching the
debugger, but I am not exploring that route right now.]

Keith

ChangeLog
2005-06-06  Keith Seitz  <keiths@redhat.com>

        * gnu/classpath/jdwp/transport/JdwpConnection.java: New file.

Index: libjava/gnu/classpath/jdwp/transport/JdwpConnection.java
===================================================================
RCS file: libjava/gnu/classpath/jdwp/transport/JdwpConnection.java
diff -N libjava/gnu/classpath/jdwp/transport/JdwpConnection.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libjava/gnu/classpath/jdwp/transport/JdwpConnection.java	6 Jun 2005 20:05:19 -0000
@@ -0,0 +1,279 @@
+/* JdwpConnection.java -- A JDWP-speaking connection
+   Copyright (C) 2005 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.jdwp.transport;
+
+import gnu.classpath.jdwp.Jdwp;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Vector;
+
+/**
+ * A connection via some transport to some JDWP-speaking entity.
+ * This is also a thread which handles all communications to/from
+ * the debugger. While access to the transport layer may be accessed by
+ * several threads, start-up and initialization should not be allowed
+ * to occur more than once.
+ *
+ * <p>This class is also a thread that is responsible for pulling
+ * packets off the wire and sticking them in a queue for packet
+ * processing threads.
+ * 
+ * @author Keith Seitz <keiths@redhat.com>
+ */
+public class JdwpConnection
+  extends Thread
+{
+  // The JDWP handshake string
+  private static final String _HANDSHAKE = "JDWP-Handshake";
+
+  // Transport method
+  private ITransport _transport;
+
+  // Command queue
+  private Vector _commandQueue;
+
+  // Shutdown flag
+  private boolean _shutdown;
+
+  /**
+   * Creates a new <code>JdwpConnection</code> instance
+   *
+   * @param transport  the transport to use for communications
+   */
+  public JdwpConnection (ITransport transport)
+  {
+    _transport = transport;
+    _commandQueue = new Vector ();
+    _shutdown = false;
+  }
+
+  /**
+   * Initializes the connection, including connecting
+   * to socket or shared memory endpoint
+   *
+   * @throws TransportException if initialization fails
+   */
+  public void initialize ()
+    throws TransportException
+  {
+    // Initialize transport (connect socket, e.g.)
+    _transport.initialize ();
+
+    // Do handshake
+    try
+      {
+	_doHandshake ();
+      }
+    catch (IOException ioe)
+      {
+	throw new TransportException (ioe);
+      }
+  }
+
+  /* Does the JDWP handshake -- this should not need synchronization
+     because this is called by VM startup code, i.e., no packet
+     processing threads have started yet. */
+  private void _doHandshake ()
+    throws IOException
+  {
+    // According to the spec, the handshake is always initiated by
+    // the debugger, regardless of whether the JVM is in client mode or
+    // server mode.
+
+    // Wait for handshake from debugger
+    DataInputStream istream
+      = new DataInputStream (_transport.getInputStream ());
+    byte[] hshake = new byte[_HANDSHAKE.length ()];
+    istream.readFully (hshake, 0, _HANDSHAKE.length ());
+    String h = new String (hshake);
+
+    if (_HANDSHAKE.equals (h))
+      {
+	// Send reply handshake
+	DataOutputStream ostream
+	  = new DataOutputStream (_transport.getOutputStream ());
+	ostream.writeBytes (_HANDSHAKE);
+	return;
+      }
+    else
+      {
+	throw new IOException ("invalid JDWP handshake (\"" + h + "\")");
+      }
+  }
+
+  /**
+   * Main run method for the thread. This thread loops waiting for
+   * packets to be read via the connection. When a packet is complete
+   * and ready for processing, it places the packet in a queue that can
+   * be accessed via <code>getPacket</code>
+   */
+  public void run ()
+  {
+    while (!_shutdown)
+      {
+	try
+	  {
+	    _readOnePacket ();
+	  }
+	catch (IOException ioe)
+	  {
+	    /* IOException can occur for two reasons:
+	       1. Lost connection with the other side
+	       2. Transport was shutdown
+	       In either case, we make sure that all of the
+	       back-end gets shutdown. */
+	    Jdwp.getInstance().shutdown ();
+	  }
+	catch (Throwable t)
+	  {
+	    System.out.println ("JdwpConnection.run: caught an exception: "
+				+ t);
+	    // Just keep going
+	  }
+      }
+  }
+
+  // Reads a single packet from the connection, adding it to the packet
+  // queue when a complete packet is ready.
+  private void _readOnePacket ()
+    throws IOException
+  {
+    DataInputStream stream;
+    synchronized (this)
+      {
+	stream = new DataInputStream (_transport.getInputStream ());
+      }
+
+    byte[] data = null;
+    synchronized (stream)
+      {
+	// Read in the packet
+	int length = stream.readInt ();
+	if (length < 11)
+	  {
+	    throw new IOException ("JDWP packet length < 11 (" 
+				   + length + ")");
+	  }
+
+	data = new byte[length];
+	data[0] = (byte) (length >>> 24);
+	data[1] = (byte) (length >>> 16);
+	data[2] = (byte) (length >>> 8);
+	data[3] = (byte) length;
+	stream.readFully (data, 4, length - 4);
+      }
+
+    JdwpPacket packet = JdwpPacket.fromBytes (data);
+    if (packet != null)
+      {
+	synchronized (_commandQueue)
+	  {
+	    _commandQueue.add (packet);
+	    _commandQueue.notifyAll ();
+	  }
+      }
+  }
+
+  /**
+   * Returns a packet from the queue of ready packets
+   *
+   * @returns  a <code>JdwpPacket</code> ready for processing
+   *           <code>null</code> when shutting down
+   */
+  public JdwpPacket getPacket ()
+  {
+    synchronized (_commandQueue)
+      {
+	while (_commandQueue.isEmpty ())
+	  {
+	    try
+	      {
+		_commandQueue.wait ();
+	      }
+	    catch (InterruptedException ie)
+	      {
+		/* PacketProcessor is interrupted
+		   when shutting down */
+		return null;
+	      }
+	  }
+
+	return (JdwpPacket) _commandQueue.remove (0);
+      }
+  }
+
+  /**
+   * Send a packet to the debugger
+   *
+   * @param pkt a <code>JdwpPacket</code> to send
+   * @throws TransportException
+   */
+  public void sendPacket (JdwpPacket pkt)
+    throws IOException
+  {
+    DataOutputStream stream;
+    synchronized (this)
+      {
+	stream = new DataOutputStream (_transport.getOutputStream ());
+      }
+
+    synchronized (stream)
+      {
+	byte[] data = pkt.toBytes ();
+	stream.write (data, 0, data.length);
+      }
+  }
+
+  /**
+   * Shutdown the connection
+   */
+  public void shutdown ()
+  {
+    synchronized (this)
+      {
+	_transport.shutdown ();
+      }
+
+    _shutdown = true;
+    this.interrupt ();
+  }
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]