Skip to content

Commit

Permalink
refactor: GDB start and wait
Browse files Browse the repository at this point in the history
Signed-off-by: Maximilien Noal <noal.maximilien@gmail.com>
  • Loading branch information
maximilien-noal committed Sep 30, 2024
1 parent a990326 commit 5da5fc0
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 37 deletions.
28 changes: 4 additions & 24 deletions src/Spice86.Core/Emulator/Gdb/GdbServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
/// </summary>
public sealed class GdbServer : IDisposable {
private readonly ILoggerService _loggerService;
private EventWaitHandle? _waitFirstConnectionHandle;
private readonly Configuration _configuration;
private bool _disposed;
private bool _isRunning = true;
Expand All @@ -26,7 +25,6 @@ public sealed class GdbServer : IDisposable {
private readonly ExecutionFlowRecorder _executionFlowRecorder;
private readonly FunctionHandler _functionHandler;
private readonly EmulatorBreakpointsManager _emulatorBreakpointsManager;
private GdbCommandHandler? _gdbCommandHandler;

/// <summary>
/// Creates a new instance of the GdbServer class with the specified parameters.
Expand Down Expand Up @@ -71,9 +69,6 @@ private void Dispose(bool disposing) {
// Prevent it from restarting when the connection is killed
_isRunning = false;
_gdbIo?.Dispose();
// Release lock if called before the first connection to gdb server has been done
_waitFirstConnectionHandle?.Set();
_waitFirstConnectionHandle?.Dispose();
_gdbServerThread?.Join();
_isRunning = false;
}
Expand All @@ -95,7 +90,6 @@ private void AcceptOneConnection(GdbIo gdbIo) {
_configuration);
gdbCommandHandler.PauseEmulator();
OnConnect();
_gdbCommandHandler = gdbCommandHandler;
while (gdbCommandHandler.IsConnected && gdbIo.IsClientConnected) {
string command = gdbIo.ReadCommand();
if (!string.IsNullOrWhiteSpace(command)) {
Expand Down Expand Up @@ -144,41 +138,27 @@ private void RunServer() {
}

/// <summary>
/// Starts the GDB server thread and waits for the initial connection to be made.
/// Starts the GDB server thread.
/// </summary>
public void StartServerAndWait() {
public void StartServer() {
if (_configuration.GdbPort is not null) {
StartServerThread();
}
}

/// <summary>
/// Starts the GDB server thread and waits for the initial connection to be made.
/// </summary>
private void StartServerThread() {
_waitFirstConnectionHandle = new AutoResetEvent(false);
_gdbServerThread = new(RunServer) {
Name = "GdbServer"
};
_gdbServerThread?.Start();
// wait for thread to start and the initial connection to be made
_waitFirstConnectionHandle.WaitOne();
// Remove the handle so that no wait
_waitFirstConnectionHandle.Dispose();
_waitFirstConnectionHandle = null;
_pauseHandler.WaitIfPaused();
}

/// <summary>
/// Sets the auto-reset event for the initial connection.
/// </summary>
private void OnConnect() {
_waitFirstConnectionHandle?.Set();
}

/// <summary>
/// Executes a single CPU instruction.
/// </summary>
public void StepInstruction() {
_gdbCommandHandler?.Step();
_pauseHandler.Resume();
}
}
10 changes: 2 additions & 8 deletions src/Spice86.Core/Emulator/ProgramExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
public sealed class ProgramExecutor : IDisposable {
private bool _disposed;
private readonly ILoggerService _loggerService;
private readonly IPauseHandler _pauseHandler;
private readonly Configuration _configuration;
private readonly GdbServer? _gdbServer;
private readonly EmulationLoop _emulationLoop;
Expand Down Expand Up @@ -63,7 +62,6 @@ public ProgramExecutor(Configuration configuration,
_configuration = configuration;
_loggerService = loggerService;
_emulatorStateSerializer = emulatorStateSerializer;
_pauseHandler = pauseHandler;
_emulationLoop = new EmulationLoop(_loggerService, functionHandler, cpu, state, timer,
emulatorBreakpointsManager, pauseHandler);
if (configuration.GdbPort.HasValue) {
Expand All @@ -88,12 +86,8 @@ public ProgramExecutor(Configuration configuration,
/// Starts the loaded program.
/// </summary>
public void Run() {
if (_gdbServer is not null) {
_gdbServer?.StartServerAndWait();
} else if (_configuration.Debug) {
_pauseHandler.RequestPause("Starting the emulated program paused was requested");
}
_emulationLoop.Run();
_gdbServer?.StartServer();
_emulationLoop.Run(_gdbServer is not null || _configuration.Debug);

if (_configuration.DumpDataOnExit is not false) {
_emulatorStateSerializer.SerializeEmulatorStateToDirectory(_configuration.RecordedDataDirectory);
Expand Down
13 changes: 8 additions & 5 deletions src/Spice86.Core/Emulator/VM/EmulationLoop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ public EmulationLoop(ILoggerService loggerService, FunctionHandler functionHandl
/// Starts and waits for the end of the emulation loop.
/// </summary>
/// <exception cref="InvalidVMOperationException">When an unhandled exception occurs. This can occur if the target program is not supported (yet).</exception>
public void Run() {
internal void Run(bool startPaused) {
try {
StartRunLoop(_functionHandler);
StartRunLoop(startPaused, _functionHandler);
} catch (HaltRequestedException) {
// Actually a signal generated code requested Exit
return;
Expand All @@ -80,13 +80,16 @@ internal void Exit() {
IsPaused = false;
}

private void StartRunLoop(FunctionHandler functionHandler) {
private void StartRunLoop(bool startPaused, FunctionHandler functionHandler) {
// Entry could be overridden and could throw exceptions
functionHandler.Call(CallType.MACHINE, _cpuState.CS, _cpuState.IP, null, null, "entry", false);
RunLoop();
RunLoop(startPaused);
}

private void RunLoop() {
private void RunLoop(bool startPaused) {
if(startPaused) {
_pauseHandler.RequestPause("Starting the emulated program paused was requested by the user.");
}
_stopwatch.Start();
if (_cpu is CfgCpu cfgCpu) {
cfgCpu.SignalEntry();
Expand Down

0 comments on commit 5da5fc0

Please sign in to comment.