2009-11-11 Geoff Norton <gnorton@novell.com>
authorGeoff Norton <grompf@sublimeintervention.com>
Wed, 11 Nov 2009 22:46:25 +0000 (22:46 -0000)
committerGeoff Norton <grompf@sublimeintervention.com>
Wed, 11 Nov 2009 22:46:25 +0000 (22:46 -0000)
* VirtualMachineManager.cs: Refactor the APIs to have async methods.
Remove a bunch of Listen overloads that are pointless.  Refactor
Launch to take a ProcessStartInfo instead of string arguments.

svn path=/trunk/mcs/; revision=145994

mcs/class/Mono.Debugger.Soft/Mono.Debugger/ChangeLog
mcs/class/Mono.Debugger.Soft/Mono.Debugger/VirtualMachineManager.cs

index 43a9071886bc2581689cf8637616b93f311b1cf6..cc1a73bd50f3e3d0f883ae21a900735c24c62b6f 100644 (file)
@@ -1,3 +1,9 @@
+2009-11-11  Geoff Norton  <gnorton@novell.com>
+
+       * VirtualMachineManager.cs: Refactor the APIs to have async methods.
+       Remove a bunch of Listen overloads that are pointless.  Refactor
+       Launch to take a ProcessStartInfo instead of string arguments.
+
 2009-11-10  Zoltan Varga  <vargaz@gmail.com>
 
        * VirtualMachineManager.cs (Launch): Close the listening socket instead of
index b9413c2bcc30f85d933b73ef873680495db6298e..6a4c796f1c7504d822f295d75285d7e0dc5b6b0f 100644 (file)
@@ -4,22 +4,11 @@ using System.Diagnostics;
 using System.IO;
 using System.Net;
 using System.Net.Sockets;
+using System.Runtime.Remoting.Messaging;
 
 namespace Mono.Debugger
 {
        public class LaunchOptions {
-               public string Runtime {
-                       get; set;
-               }
-
-               public bool RedirectStandardOutput {
-                       get; set;
-               }
-
-               public bool RedirectStandardError {
-                       get; set;
-               }
-
                public string AgentArgs {
                        get; set;
                }
@@ -31,75 +20,28 @@ namespace Mono.Debugger
 
        public class VirtualMachineManager
        {
+               private delegate VirtualMachine LaunchCallback (Process p, Socket socket);
+               private delegate VirtualMachine ListenCallback (Socket dbg_sock, Socket con_sock); 
+
                internal VirtualMachineManager () {
                }
 
-               /*
-                * Launch a new virtual machine with the provided arguments.
-                */
-               public static VirtualMachine Launch (string[] args, LaunchOptions options = null) {
-                       if (args == null)
-                               throw new ArgumentNullException ("args");
-                       Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
-                       socket.Bind (new IPEndPoint (IPAddress.Loopback, 0));
-                       socket.Listen (1000);
-
-                       IPEndPoint endPoint = (IPEndPoint)socket.LocalEndPoint;
-                       string addressString = endPoint.Address.ToString () + ":" + endPoint.Port.ToString ();
-
-                       string runtime = "mono";
-                       bool valgrind = options != null && options.Valgrind;
-
-                       string extra_args = "";
-
-                       if (options != null && options.Runtime != null)
-                               runtime = options.Runtime;
-                       if (options != null && options.AgentArgs != null)
-                               extra_args = "," + options.AgentArgs;
-
-                       string agent_args = "--debug --debugger-agent=transport=dt_socket,address=" + addressString + extra_args;
-                       if (valgrind)
-                               agent_args = runtime + " " + agent_args;
-
-                       ProcessStartInfo start_info = new ProcessStartInfo ();
-                       start_info.FileName = valgrind ? "valgrind" : runtime;
-                       start_info.Arguments = agent_args + " " + String.Join (" ", args);
-                       start_info.UseShellExecute = false;
-                       if (options != null && options.RedirectStandardOutput)
-                               start_info.RedirectStandardOutput = true;
-                       if (options != null && options.RedirectStandardError)
-                               start_info.RedirectStandardError = true;
-                       Process p = Process.Start (start_info);
-                       bool exited = false;
-                       /* Handle the debuggee exiting so we don't block in Accept () forever */
-                       p.Exited += delegate (object sender, EventArgs eargs) {
-                               exited = true;
-                               socket.Close ();
-                       };
-
-                       /* 
-                        * Wait until we are connected to the debuggee so the caller gets 
-                        * back a fully usable vm object.
-                        * FIXME: This might block forever.
-                        */
+               public static VirtualMachine LaunchInternal (Process p, Socket socket) {
                        Socket accepted = null;
                        try {
                                accepted = socket.Accept ();
                        } catch (ObjectDisposedException) {
-                               if (exited)
-                                       throw new IOException ("Debuggee process exited.");
-                               else
-                                       throw;
+                               throw;
                        }
 
                        Connection conn = new Connection (accepted);
 
                        VirtualMachine vm = new VirtualMachine (p, conn);
 
-                       if (options != null && options.RedirectStandardOutput)
+                       if (p.StartInfo.RedirectStandardOutput)
                                vm.StandardOutput = p.StandardOutput;
                        
-                       if (options != null && options.RedirectStandardError)
+                       if (p.StartInfo.RedirectStandardError)
                                vm.StandardError = p.StandardError;
 
                        conn.EventHandler = new EventHandler (vm);
@@ -109,44 +51,96 @@ namespace Mono.Debugger
                        return vm;
                }
 
-               /*
-                * Wait for a virtual machine to connect at the specified address.
-                */
-               public static VirtualMachine Listen (IPAddress address, int debugger_port, int console_port) {
-                       if (address == null)
-                               throw new ArgumentNullException ("address");
+               public static IAsyncResult BeginLaunch (ProcessStartInfo info, AsyncCallback callback, LaunchOptions options = null) {
+                       if (info == null)
+                               throw new ArgumentNullException ("info");
 
-                       IPEndPoint dbg_ep = new IPEndPoint (address, debugger_port);
-                       IPEndPoint con_ep = new IPEndPoint (address, console_port);
+                       Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+                       socket.Bind (new IPEndPoint (IPAddress.Loopback, 0));
+                       socket.Listen (1000);
+                       IPEndPoint ep = (IPEndPoint) socket.LocalEndPoint;
+
+                       // We need to inject our arguments into the psi
+                       info.Arguments = string.Format ("{0} --debug --debugger-agent=transport=dt_socket,address={1}:{2}{3} {4}", 
+                                                               options == null || !options.Valgrind ? "" : info.FileName,
+                                                               ep.Address,
+                                                               ep.Port,
+                                                               options == null || options.AgentArgs == null ? "" : "," + options.AgentArgs,
+                                                               info.Arguments);
+
+                       if (options != null && options.Valgrind)
+                               info.FileName = "valgrind";
+                               
+                       Process p = Process.Start (info);
+                       
+                       p.Exited += delegate (object sender, EventArgs eargs) {
+                               socket.Close ();
+                       };
 
-                       Socket con_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
-                       Socket dbg_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
-                       con_sock.Bind (con_ep);
-                       dbg_sock.Bind (dbg_ep);
-                       con_sock.Listen (1000);
-                       dbg_sock.Listen (1000);
+                       LaunchCallback c = new LaunchCallback (LaunchInternal);
+                       return c.BeginInvoke (p, socket, callback, socket);
+               }
 
-                       return Listen (con_sock, dbg_sock);
+               public static VirtualMachine EndLaunch (IAsyncResult asyncResult) {
+                       if (asyncResult == null)
+                               throw new ArgumentNullException ("asyncResult");
+
+                       if (!asyncResult.IsCompleted)
+                               asyncResult.AsyncWaitHandle.WaitOne ();
+
+                       AsyncResult async = (AsyncResult) asyncResult;
+                       LaunchCallback cb = (LaunchCallback) async.AsyncDelegate;
+                       return cb.EndInvoke (asyncResult);
                }
 
-               public static VirtualMachine Listen (Socket con_sock, Socket dbg_sock) {
-                       /* 
-                        * FIXME: This might block forever.
-                        */
-                       Socket con_accepted = con_sock.Accept ();
-                       Socket dbg_accepted = dbg_sock.Accept ();
+               public static VirtualMachine Launch (ProcessStartInfo info, LaunchOptions options = null) {
+                       return EndLaunch (BeginLaunch (info, null, null));
+               }
+
+               public static VirtualMachine ListenInternal (Socket dbg_sock, Socket con_sock) {
+                       Socket con_acc = null;
+                       Socket dbg_acc = null;
+
+                       if (con_sock != null) {
+                               try {
+                                       con_acc = con_sock.Accept ();
+                               } catch (ObjectDisposedException) {
+                                       try {
+                                               dbg_sock.Close ();
+                                       } catch {}
+                                       throw;
+                               }
+                       }
+                                               
+                       try {
+                               dbg_acc = dbg_sock.Accept ();
+                       } catch (ObjectDisposedException) {
+                               if (con_sock != null) {
+                                       try {
+                                               con_sock.Close ();
+                                               con_acc.Close ();
+                                       } catch {}
+                               }
+                               throw;
+                       }
+
+                       if (con_sock != null) {
+                               con_sock.Disconnect (false);
+                               con_sock.Close ();
+                       }
 
-                       con_sock.Disconnect (false);
                        dbg_sock.Disconnect (false);
-                       con_sock.Close ();
                        dbg_sock.Close ();
 
-                       Connection conn = new Connection (dbg_accepted);
+                       Connection conn = new Connection (dbg_acc);
 
                        VirtualMachine vm = new VirtualMachine (null, conn);
 
-                       vm.StandardOutput = new StreamReader (new NetworkStream (con_accepted));
-                       vm.StandardError = null;
+                       if (con_acc != null) {
+                               vm.StandardOutput = new StreamReader (new NetworkStream (con_acc));
+                               vm.StandardError = null;
+                       }
+
                        conn.EventHandler = new EventHandler (vm);
 
                        vm.connect ();
@@ -154,34 +148,42 @@ namespace Mono.Debugger
                        return vm;
                }
 
-               /*
-                * Wait for a virtual machine to connect at the specified address.
-                */
-               public static VirtualMachine Listen (IPEndPoint endpoint) {
-                       if (endpoint == null)
-                               throw new ArgumentNullException ("endpoint");
-
-                       Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
-                       socket.Bind (endpoint);
-                       socket.Listen (1000);
+               public static IAsyncResult BeginListen (IPEndPoint dbg_ep, AsyncCallback callback) {
+                       return BeginListen (dbg_ep, null, callback);
+               }
 
-                       /* 
-                        * FIXME: This might block forever.
-                        */
-                       Socket accepted = socket.Accept ();
+               public static IAsyncResult BeginListen (IPEndPoint dbg_ep, IPEndPoint con_ep, AsyncCallback callback) {
+                       Socket dbg_sock = null;
+                       Socket con_sock = null;
 
-                       socket.Disconnect (false);
-                       socket.Close ();
+                       dbg_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+                       dbg_sock.Bind (dbg_ep);
+                       dbg_sock.Listen (1000);
 
-                       Connection conn = new Connection (accepted);
+                       if (con_ep != null) {
+                               con_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+                               con_sock.Bind (con_ep);
+                               con_sock.Listen (1000);
+                       }
+                       
+                       ListenCallback c = new ListenCallback (ListenInternal);
+                       return c.BeginInvoke (dbg_sock, con_sock, callback, con_sock ?? dbg_sock);
+               }
 
-                       VirtualMachine vm = new VirtualMachine (null, conn);
+               public static VirtualMachine EndListen (IAsyncResult asyncResult) {
+                       if (asyncResult == null)
+                               throw new ArgumentNullException ("asyncResult");
 
-                       conn.EventHandler = new EventHandler (vm);
+                       if (!asyncResult.IsCompleted)
+                               asyncResult.AsyncWaitHandle.WaitOne ();
 
-                       vm.connect ();
+                       AsyncResult async = (AsyncResult) asyncResult;
+                       ListenCallback cb = (ListenCallback) async.AsyncDelegate;
+                       return cb.EndInvoke (asyncResult);
+               }
 
-                       return vm;
+               public static VirtualMachine Listen (IPEndPoint dbg_ep, IPEndPoint con_ep = null) { 
+                       return EndListen (BeginListen (dbg_ep, con_ep, null));
                }
 
                /*
@@ -204,5 +206,5 @@ namespace Mono.Debugger
 
                        return vm;
                }
-    }
+       }
 }