Switch to NetMQ for inter-process debugging

This commit is contained in:
Yoshi Askharoun
2023-05-22 21:44:05 -05:00
parent 1d36315297
commit 49d8ae6323
12 changed files with 167 additions and 101 deletions
+12 -2
View File
@@ -6,6 +6,7 @@
using Microsoft.Iris.Animations;
using Microsoft.Iris.Data;
using Microsoft.Iris.Debug;
using Microsoft.Iris.Input;
using Microsoft.Iris.Library;
using Microsoft.Iris.Markup;
@@ -135,7 +136,11 @@ namespace Microsoft.Iris
get => DllResources.StaticDllResourcesOnly;
}
public static Debug.DebugSettings DebugSettings { get; } = new();
public static DebugSettings DebugSettings { get; } = new();
internal static IDebuggerServer Debugger { get; private set; }
public static event EventHandler DebuggerServerReady;
public static void Initialize()
{
@@ -187,7 +192,12 @@ namespace Microsoft.Iris
ErrorManager.OnErrors += new NotifyErrorBatch(NotifyErrorBatchHandler);
Debug.Trace.Initialize();
Debug.BridgeServer.Start(null);
if (DebugSettings.DebugConnectionUri != null)
{
Debugger = new ZmqDebuggerServer(DebugSettings.DebugConnectionUri);
DebuggerServerReady?.Invoke(Debugger, EventArgs.Empty);
}
MarkupSystem.Startup(!fullInitialization);
StaticServices.Initialize();
-58
View File
@@ -1,58 +0,0 @@
using CoreRemoting;
using CoreRemoting.DependencyInjection;
using CoreRemoting.Serialization.Binary;
using System;
namespace Microsoft.Iris.Debug;
internal class BridgeServer : IBridge, IDisposable
{
private static RemotingServer _server;
public static IBridge Current { get; private set; }
public event EventHandler<Data.InterpreterEntry> InterpreterStep;
public event Action<string> DispatcherStep;
public static void Start(ServerConfig config)
{
_server = new RemotingServer(new ServerConfig
{
HostName = "localhost",
NetworkPort = 9090,
MessageEncryption = false,
Serializer = new BinarySerializerAdapter(),
RegisterServicesAction = container =>
{
container.RegisterService<IBridge, BridgeServer>(ServiceLifetime.Singleton);
}
});
Current = _server.ServiceRegistry.GetService<IBridge>();
_server.Error += OnServerError;
_server.BeforeCall += (_, ctx) =>
{
};
_server.Start();
}
private static void OnServerError(object sender, Exception e)
{
}
public void LogInterpreterOpCode(object context, Data.InterpreterEntry entry)
{
InterpreterStep?.Invoke(context, entry);
}
public void LogDispatcher(string message)
{
DispatcherStep?.Invoke(message);
}
public void Dispose() => _server.Dispose();
}
+2 -3
View File
@@ -1,5 +1,4 @@
using CoreRemoting;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Xml;
#if NET40_OR_GREATER || NET6_0_OR_GREATER
@@ -23,7 +22,7 @@ namespace Microsoft.Iris.Debug
public List<string> Breakpoints { get; } = new List<string>();
public ServerConfig DebugServerConfig { get; set; }
public string DebugConnectionUri { get; set; }
}
public class DecompilationResult
@@ -0,0 +1,9 @@
namespace Microsoft.Iris.Debug;
public enum DebuggerMessageType : int
{
Null = 0,
InterpreterOpCode,
DispatcherStep,
}
-33
View File
@@ -1,33 +0,0 @@
using System;
namespace Microsoft.Iris.Debug;
/// <summary>
/// The contract between the UIX runtime and debuggers.
/// </summary>
public interface IBridge
{
/// <summary>
/// Fired when the UIX interpreter steps forward.
/// </summary>
event EventHandler<Data.InterpreterEntry> InterpreterStep;
/// <summary>
/// Fired when the UIX dispatcher executes another call from the queue.
/// </summary>
event Action<string> DispatcherStep;
/// <summary>
/// Logs the context, opcode, and arguments of an instruction
/// executed by <c>Microsoft.Iris.Markup.Interpreter</c>.
/// </summary>
/// <param name="context"></param>
/// <param name="entry"></param>
public void LogInterpreterOpCode(object context, Data.InterpreterEntry entry);
/// <summary>
/// Logs the string representation of a dispatcher step.
/// </summary>
/// <param name="message"></param>
public void LogDispatcher(string message);
}
@@ -0,0 +1,17 @@
using Microsoft.Iris.Debug.Data;
using System;
namespace Microsoft.Iris.Debug;
public interface IDebuggerClient
{
/// <summary>
/// Fired when the UIX interpreter steps forward.
/// </summary>
event EventHandler<InterpreterEntry> InterpreterStep;
/// <summary>
/// Fired when the UIX dispatcher executes another call from the queue.
/// </summary>
event Action<string> DispatcherStep;
}
@@ -0,0 +1,18 @@
using Microsoft.Iris.Debug.Data;
namespace Microsoft.Iris.Debug;
internal interface IDebuggerServer
{
/// <summary>
/// Logs the context, opcode, and arguments of an instruction
/// executed by <c>Microsoft.Iris.Markup.Interpreter</c>.
/// </summary>
public void LogInterpreterOpCode(object context, InterpreterEntry entry);
/// <summary>
/// Logs the string representation of a dispatcher step.
/// </summary>
/// <param name="message"></param>
public void LogDispatcher(string message);
}
@@ -0,0 +1,56 @@
using Microsoft.Iris.Debug.Data;
using NetMQ;
using NetMQ.Sockets;
using System;
using System.Text;
namespace Microsoft.Iris.Debug;
public class ZmqDebuggerClient : IDebuggerClient, IDisposable
{
private readonly SubscriberSocket _subSocket;
public event EventHandler<InterpreterEntry> InterpreterStep;
public event Action<string> DispatcherStep;
public ZmqDebuggerClient(string connectionUri)
{
_subSocket = new();
_subSocket.Connect(connectionUri);
_subSocket.SubscribeToAnyTopic();
System.Threading.Thread th = new(MessageRecieveLoop);
th.Start();
}
public void Dispose() => _subSocket.Dispose();
private void MessageRecieveLoop()
{
while (!_subSocket.IsDisposed)
{
var type = RecieveDebuggerMessage(_subSocket, out var bytes);
switch (type)
{
case DebuggerMessageType.InterpreterOpCode:
string entry = Encoding.Unicode.GetString(bytes);
InterpreterStep?.Invoke(this, null);
break;
case DebuggerMessageType.DispatcherStep:
string message = Encoding.Unicode.GetString(bytes);
DispatcherStep?.Invoke(message);
break;
}
}
}
private DebuggerMessageType RecieveDebuggerMessage(SubscriberSocket socket, out byte[] bytes)
{
var frames = socket.ReceiveMultipartBytes(2);
bytes = frames[1];
return (DebuggerMessageType)BitConverter.ToInt32(frames[0], 0);
}
}
@@ -0,0 +1,48 @@
using NetMQ;
using NetMQ.Sockets;
using System;
using System.Text;
namespace Microsoft.Iris.Debug;
internal class ZmqDebuggerServer : IDebuggerServer, IDisposable
{
public static IDebuggerServer Current { get; private set; }
private readonly PublisherSocket _pubSocket;
private readonly byte[][] _messageFrame = new byte[2][];
public ZmqDebuggerServer(string connectionUri)
{
_pubSocket = new();
_pubSocket.Bind(connectionUri);
Current = this;
}
public void LogInterpreterOpCode(object context, Data.InterpreterEntry entry)
{
SendDebuggerMessage(DebuggerMessageType.InterpreterOpCode, entry.ToString());
}
public void LogDispatcher(string message)
{
SendDebuggerMessage(DebuggerMessageType.DispatcherStep, message);
}
public void Dispose() => _pubSocket.Dispose();
private void SendDebuggerMessage(DebuggerMessageType type, string message, Encoding encoding = null)
{
var messageBytes = (encoding ?? Encoding.Unicode).GetBytes(message);
SendDebuggerMessage(type, messageBytes);
}
private void SendDebuggerMessage(DebuggerMessageType type, byte[] bytes)
{
_messageFrame[0] = BitConverter.GetBytes((int)type);
_messageFrame[1] = bytes;
_pubSocket.SendMultipartBytes(_messageFrame);
}
}
+3 -3
View File
@@ -66,7 +66,7 @@ namespace Microsoft.Iris.Markup
bool errorsDetected = false;
object result = null;
bool wasInDebugState = false;
bool debugging = BridgeServer.Current != null;
bool debugging = Application.Debugger != null;
while (!errorsDetected)
{
@@ -670,7 +670,7 @@ namespace Microsoft.Iris.Markup
}
}
BridgeServer.Current?.LogInterpreterOpCode(opCode, entry);
Application.Debugger?.LogInterpreterOpCode(opCode, entry);
}
while (stack.Count > count)
{
@@ -1630,7 +1630,7 @@ namespace Microsoft.Iris.Markup
}
}
BridgeServer.Current?.LogInterpreterOpCode(opCode, entry);
Application.Debugger?.LogInterpreterOpCode(opCode, entry);
if (stack.Count != xmlStack.Count)
throw new InvalidOperationException(
+1 -1
View File
@@ -73,7 +73,7 @@ namespace Microsoft.Iris.Queues
QueueItem nextItem = queue.GetNextItem();
if (nextItem != null)
{
BridgeServer.Current.LogDispatcher(nextItem.ToDebugPacketString());
Application.Debugger.LogDispatcher(nextItem.ToDebugPacketString());
nextItem.Dispatch();
}
else