Hello,
I would like to revisit this topic again. I don't know if anyone
attempting to implement JDWP is having startup problems, but I certainly
am with gij. Basically, we need to know exactly when the entire JDWP
backend is ready to go, otherwise we end up trying to send event
notifications before the debugger is attached and all kinds of other mess.
So I've come up with a rather hacky approach to do this synchronization.
The idea is simple: gnu.classpath.jdwp.Jdwp, which already does
initialization in its own thread, now contains basically a condition
variable. When the condition variable hits a certain count (indicating
that all subcomponents are initialized), the thread sets the global
"isDebugging" flag, and exits. Thus the caller can simply join or
WaitForSingleObject on that thread. When it exits, everything is ready.
While this *is* hacky (a thread exit doesn't really sound like a very
explicit/obvious way of implementing this), but it is extremely simple.
I tried using "standard" Object.wait-like stuff for this, but it seems
to me that while this would be trivial to implement with gcj, it might
be quite sloppy in other VMs which have to use JNI. [Besides I haven't
gotten that to work properly with gij -- it seems I can't get
something(s) set up sufficiently to allow Object.wait to be called.]
I've attached the patches for this scheme. What do people think? [I'll
include a changelog entry for the heck of it, I guess.]
I would appreciate comments (for or against).
Keith
ChangeLog
2006-06-15 Keith Seitz <[EMAIL PROTECTED]>
* gnu/classpath/jdwp/Jdwp.java (_initLock): New field.
(_initCount): New field.
(Jdwp): Don't set isDebugging until fully initialized.
(subcomponentInitialized): New method.
(run): Wait for PacketProcessor and JdwpConnection to
startup, then set isDebugging, and then let this thread
die.
* gnu/classpath/jdwp/transport/JdwpConnection.java
(run): Add synchronization notification.
* gnu/classpath/jdwp/processor/PacketProcessor.java
(run): Likewise.
Index: gnu/classpath/jdwp/Jdwp.java
===================================================================
RCS file: /sources/classpath/classpath/gnu/classpath/jdwp/Jdwp.java,v
retrieving revision 1.6
diff -u -p -r1.6 Jdwp.java
--- gnu/classpath/jdwp/Jdwp.java 16 Mar 2006 23:26:10 -0000 1.6
+++ gnu/classpath/jdwp/Jdwp.java 15 Jun 2006 22:00:34 -0000
@@ -56,6 +56,9 @@ import java.util.HashMap;
/**
* Main interface from the virtual machine to the JDWP back-end.
*
+ * The thread created by this class is only used for initialization.
+ * Once it exits, the JDWP backend is fully initialized.
+ *
* @author Keith Seitz ([EMAIL PROTECTED])
*/
public class Jdwp
@@ -65,7 +68,8 @@ public class Jdwp
private static Jdwp _instance = null;
/**
- * Are we debugging?
+ * Are we debugging? Only true if debugging
+ * *and* initialized.
*/
public static boolean isDebugging = false;
@@ -89,13 +93,16 @@ public class Jdwp
// A thread group for the JDWP threads
private ThreadGroup _group;
+ // Initialization synchronization
+ private Object _initLock = new Object ();
+ private int _initCount = 0;
+
/**
* constructor
*/
public Jdwp ()
{
_shutdown = false;
- isDebugging = true;
_instance = this;
}
@@ -271,17 +278,47 @@ public class Jdwp
}
}
+ /**
+ * Allows subcomponents to specify that they are
+ * initialized.
+ *
+ * Subcomponents include JdwpConnection and PacketProcessor.
+ */
+ public void subcomponentInitialized ()
+ {
+ synchronized (_initLock)
+ {
+ ++_initCount;
+ _initLock.notify ();
+ }
+ }
+
public void run ()
{
try
{
_doInitialization ();
+
+ /* We need a little internal synchronization here, so that
+ when this thread dies, the back-end will be fully initialized,
+ ready to start servicing the VM and debugger. */
+ while (_initCount != 2)
+ {
+ synchronized (_initLock)
+ {
+ _initLock.wait ();
+ }
+ }
+ _initLock = null;
}
catch (Throwable t)
{
System.out.println ("Exception in JDWP back-end: " + t);
System.exit (1);
}
+
+ // Now we are finally ready and initialized
+ isDebugging = true;
}
// A helper function to process the configure string "-Xrunjdwp:..."
Index: gnu/classpath/jdwp/transport/JdwpConnection.java
===================================================================
RCS file: /sources/classpath/classpath/gnu/classpath/jdwp/transport/JdwpConnection.java,v
retrieving revision 1.5
diff -u -p -r1.5 JdwpConnection.java
--- gnu/classpath/jdwp/transport/JdwpConnection.java 3 Sep 2005 00:22:30 -0000 1.5
+++ gnu/classpath/jdwp/transport/JdwpConnection.java 15 Jun 2006 22:00:34 -0000
@@ -1,5 +1,5 @@
/* JdwpConnection.java -- A JDWP-speaking connection
- Copyright (C) 2005 Free Software Foundation
+ Copyright (C) 2005, 2006 Free Software Foundation
This file is part of GNU Classpath.
@@ -165,6 +165,10 @@ public class JdwpConnection
*/
public void run ()
{
+ // Notify initialization thread (gnu.classpath.jdwp.Jdwp) that
+ // the JdwpConnection thread is ready.
+ Jdwp.getDefault().subcomponentInitialized ();
+
while (!_shutdown)
{
try
Index: gnu/classpath/jdwp/processor/PacketProcessor.java
===================================================================
RCS file: /sources/classpath/classpath/gnu/classpath/jdwp/processor/PacketProcessor.java,v
retrieving revision 1.5
diff -u -p -r1.5 PacketProcessor.java
--- gnu/classpath/jdwp/processor/PacketProcessor.java 27 Jul 2005 19:04:14 -0000 1.5
+++ gnu/classpath/jdwp/processor/PacketProcessor.java 15 Jun 2006 22:00:34 -0000
@@ -1,6 +1,6 @@
/* PacketProcessor.java -- a thread which processes command packets
from the debugger
- Copyright (C) 2005 Free Software Foundation
+ Copyright (C) 2005, 2006 Free Software Foundation
This file is part of GNU Classpath.
@@ -137,6 +137,10 @@ public class PacketProcessor
*/
public Object run ()
{
+ // Notify initialization thread (gnu.classpath.jdwp.Jdwp) that
+ // the PacketProcessor thread is ready.
+ Jdwp.getDefault().subcomponentInitialized ();
+
try
{
while (!_shutdown)
@@ -144,7 +148,7 @@ public class PacketProcessor
_processOnePacket ();
}
}
- catch (IOException ex)
+ catch (Exception ex)
{
ex.printStackTrace();
}