This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
[RFA/JDWP] JdwpConnection
- From: Keith Seitz <keiths at redhat dot com>
- To: GCJ Patches <java-patches at gcc dot gnu dot org>
- Cc: classpath patches <classpath-patches at gnu dot org>
- Date: Mon, 06 Jun 2005 13:15:44 -0700
- Subject: [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 ();
+ }
+}