Fixing debugger startup race.
This commit is contained in:
parent
19901c4759
commit
122114d1d1
|
@ -10,6 +10,8 @@
|
||||||
#ifndef XENIA_DEBUG_DEBUG_SERVER_H_
|
#ifndef XENIA_DEBUG_DEBUG_SERVER_H_
|
||||||
#define XENIA_DEBUG_DEBUG_SERVER_H_
|
#define XENIA_DEBUG_DEBUG_SERVER_H_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include "xenia/cpu/function.h"
|
#include "xenia/cpu/function.h"
|
||||||
#include "xenia/cpu/processor.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/debug/breakpoint.h"
|
#include "xenia/debug/breakpoint.h"
|
||||||
|
@ -27,6 +29,8 @@ class DebugServer {
|
||||||
|
|
||||||
virtual bool Initialize() = 0;
|
virtual bool Initialize() = 0;
|
||||||
|
|
||||||
|
virtual void PostSynchronous(std::function<void()> fn) = 0;
|
||||||
|
|
||||||
// TODO(benvanik): better thread type (XThread?)
|
// TODO(benvanik): better thread type (XThread?)
|
||||||
// virtual void OnThreadCreated(ThreadState* thread_state) = 0;
|
// virtual void OnThreadCreated(ThreadState* thread_state) = 0;
|
||||||
// virtual void OnThreadDestroyed(ThreadState* thread_state) = 0;
|
// virtual void OnThreadDestroyed(ThreadState* thread_state) = 0;
|
||||||
|
|
|
@ -123,7 +123,7 @@ void Debugger::PreLaunch() {
|
||||||
|
|
||||||
// Start paused.
|
// Start paused.
|
||||||
execution_state_ = ExecutionState::kRunning;
|
execution_state_ = ExecutionState::kRunning;
|
||||||
Interrupt();
|
server_->PostSynchronous([this]() { Interrupt(); });
|
||||||
} else {
|
} else {
|
||||||
// Start running.
|
// Start running.
|
||||||
execution_state_ = ExecutionState::kRunning;
|
execution_state_ = ExecutionState::kRunning;
|
||||||
|
|
|
@ -44,6 +44,8 @@ bool GdbServer::Initialize() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GdbServer::PostSynchronous(std::function<void()> fn) { assert_always(); }
|
||||||
|
|
||||||
void GdbServer::AcceptClient(std::unique_ptr<Socket> client) {
|
void GdbServer::AcceptClient(std::unique_ptr<Socket> client) {
|
||||||
// If we have an existing client, kill it and join its thread.
|
// If we have an existing client, kill it and join its thread.
|
||||||
if (client_) {
|
if (client_) {
|
||||||
|
|
|
@ -32,6 +32,8 @@ class GdbServer : public DebugServer {
|
||||||
|
|
||||||
bool Initialize() override;
|
bool Initialize() override;
|
||||||
|
|
||||||
|
void PostSynchronous(std::function<void()> fn) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void AcceptClient(std::unique_ptr<Socket> client);
|
void AcceptClient(std::unique_ptr<Socket> client);
|
||||||
bool HandleClientEvent();
|
bool HandleClientEvent();
|
||||||
|
|
|
@ -44,6 +44,8 @@ bool MIServer::Initialize() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MIServer::PostSynchronous(std::function<void()> fn) { assert_always(); }
|
||||||
|
|
||||||
void MIServer::AcceptClient(std::unique_ptr<Socket> client) {
|
void MIServer::AcceptClient(std::unique_ptr<Socket> client) {
|
||||||
// If we have an existing client, kill it and join its thread.
|
// If we have an existing client, kill it and join its thread.
|
||||||
if (client_) {
|
if (client_) {
|
||||||
|
|
|
@ -32,6 +32,8 @@ class MIServer : public DebugServer {
|
||||||
|
|
||||||
bool Initialize() override;
|
bool Initialize() override;
|
||||||
|
|
||||||
|
void PostSynchronous(std::function<void()> fn) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void AcceptClient(std::unique_ptr<Socket> client);
|
void AcceptClient(std::unique_ptr<Socket> client);
|
||||||
bool HandleClientEvent();
|
bool HandleClientEvent();
|
||||||
|
|
|
@ -42,6 +42,8 @@ XdpServer::XdpServer(Debugger* debugger)
|
||||||
XdpServer::~XdpServer() = default;
|
XdpServer::~XdpServer() = default;
|
||||||
|
|
||||||
bool XdpServer::Initialize() {
|
bool XdpServer::Initialize() {
|
||||||
|
post_event_ = xe::threading::Event::CreateAutoResetEvent(false);
|
||||||
|
|
||||||
socket_server_ = SocketServer::Create(uint16_t(FLAGS_xdp_server_port),
|
socket_server_ = SocketServer::Create(uint16_t(FLAGS_xdp_server_port),
|
||||||
[this](std::unique_ptr<Socket> client) {
|
[this](std::unique_ptr<Socket> client) {
|
||||||
AcceptClient(std::move(client));
|
AcceptClient(std::move(client));
|
||||||
|
@ -54,6 +56,19 @@ bool XdpServer::Initialize() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XdpServer::PostSynchronous(std::function<void()> fn) {
|
||||||
|
xe::threading::Fence fence;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(post_mutex_);
|
||||||
|
post_queue_.push_back([&fence, fn]() {
|
||||||
|
fn();
|
||||||
|
fence.Signal();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
post_event_->Set();
|
||||||
|
fence.Wait();
|
||||||
|
}
|
||||||
|
|
||||||
void XdpServer::AcceptClient(std::unique_ptr<Socket> client) {
|
void XdpServer::AcceptClient(std::unique_ptr<Socket> client) {
|
||||||
// If we have an existing client, kill it and join its thread.
|
// If we have an existing client, kill it and join its thread.
|
||||||
if (client_) {
|
if (client_) {
|
||||||
|
@ -85,11 +100,35 @@ void XdpServer::AcceptClient(std::unique_ptr<Socket> client) {
|
||||||
// Main loop.
|
// Main loop.
|
||||||
bool running = true;
|
bool running = true;
|
||||||
while (running) {
|
while (running) {
|
||||||
auto wait_result = xe::threading::Wait(client_->wait_handle(), true);
|
xe::threading::WaitHandle* wait_handles[] = {
|
||||||
switch (wait_result) {
|
client_->wait_handle(), post_event_.get(),
|
||||||
|
};
|
||||||
|
auto wait_result = xe::threading::WaitMultiple(
|
||||||
|
wait_handles, xe::countof(wait_handles), false, true);
|
||||||
|
switch (wait_result.first) {
|
||||||
case xe::threading::WaitResult::kSuccess:
|
case xe::threading::WaitResult::kSuccess:
|
||||||
// Event (read or close).
|
// Event (read or close).
|
||||||
|
switch (wait_result.second) {
|
||||||
|
case 0: {
|
||||||
running = HandleClientEvent();
|
running = HandleClientEvent();
|
||||||
|
} break;
|
||||||
|
case 1: {
|
||||||
|
bool has_remaining = true;
|
||||||
|
while (has_remaining) {
|
||||||
|
std::function<void()> fn;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(post_mutex_);
|
||||||
|
fn = std::move(post_queue_.front());
|
||||||
|
post_queue_.pop_front();
|
||||||
|
has_remaining = !post_queue_.empty();
|
||||||
|
if (!has_remaining) {
|
||||||
|
post_event_->Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
case xe::threading::WaitResult::kAbandoned:
|
case xe::threading::WaitResult::kAbandoned:
|
||||||
case xe::threading::WaitResult::kFailed:
|
case xe::threading::WaitResult::kFailed:
|
||||||
|
|
|
@ -10,7 +10,9 @@
|
||||||
#ifndef XENIA_DEBUG_SERVER_XDP_XDP_SERVER_H_
|
#ifndef XENIA_DEBUG_SERVER_XDP_XDP_SERVER_H_
|
||||||
#define XENIA_DEBUG_SERVER_XDP_XDP_SERVER_H_
|
#define XENIA_DEBUG_SERVER_XDP_XDP_SERVER_H_
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "xenia/base/socket.h"
|
#include "xenia/base/socket.h"
|
||||||
#include "xenia/base/threading.h"
|
#include "xenia/base/threading.h"
|
||||||
|
@ -33,6 +35,8 @@ class XdpServer : public DebugServer {
|
||||||
|
|
||||||
bool Initialize() override;
|
bool Initialize() override;
|
||||||
|
|
||||||
|
void PostSynchronous(std::function<void()> fn) override;
|
||||||
|
|
||||||
void OnExecutionContinued() override;
|
void OnExecutionContinued() override;
|
||||||
void OnExecutionInterrupted() override;
|
void OnExecutionInterrupted() override;
|
||||||
|
|
||||||
|
@ -54,6 +58,11 @@ class XdpServer : public DebugServer {
|
||||||
|
|
||||||
std::unique_ptr<Socket> client_;
|
std::unique_ptr<Socket> client_;
|
||||||
std::unique_ptr<xe::threading::Thread> client_thread_;
|
std::unique_ptr<xe::threading::Thread> client_thread_;
|
||||||
|
|
||||||
|
std::mutex post_mutex_;
|
||||||
|
std::unique_ptr<xe::threading::Event> post_event_;
|
||||||
|
std::list<std::function<void()>> post_queue_;
|
||||||
|
|
||||||
std::vector<uint8_t> receive_buffer_;
|
std::vector<uint8_t> receive_buffer_;
|
||||||
proto::PacketReader packet_reader_;
|
proto::PacketReader packet_reader_;
|
||||||
proto::PacketWriter packet_writer_;
|
proto::PacketWriter packet_writer_;
|
||||||
|
|
|
@ -218,8 +218,10 @@ X_STATUS XUserModule::Launch(uint32_t flags) {
|
||||||
XELOGI("Launching module...");
|
XELOGI("Launching module...");
|
||||||
|
|
||||||
// Create a thread to run in.
|
// Create a thread to run in.
|
||||||
auto thread = object_ref<XThread>(
|
// We start suspended so we can run the debugger prep.
|
||||||
new XThread(kernel_state(), stack_size_, 0, entry_point_, 0, 0, true));
|
auto thread = object_ref<XThread>(new XThread(kernel_state(), stack_size_, 0,
|
||||||
|
entry_point_, 0,
|
||||||
|
X_CREATE_SUSPENDED, true));
|
||||||
|
|
||||||
X_STATUS result = thread->Create();
|
X_STATUS result = thread->Create();
|
||||||
if (XFAILED(result)) {
|
if (XFAILED(result)) {
|
||||||
|
@ -227,6 +229,16 @@ X_STATUS XUserModule::Launch(uint32_t flags) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Waits for a debugger client, if desired.
|
||||||
|
if (emulator()->debugger()) {
|
||||||
|
emulator()->debugger()->PreLaunch();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resume the thread now.
|
||||||
|
// If the debugger has requested a suspend this will just decrement the
|
||||||
|
// suspend count without resuming it until the debugger wants.
|
||||||
|
thread->Resume();
|
||||||
|
|
||||||
// Wait until thread completes.
|
// Wait until thread completes.
|
||||||
thread->Wait(0, 0, 0, nullptr);
|
thread->Wait(0, 0, 0, nullptr);
|
||||||
|
|
||||||
|
|
|
@ -179,11 +179,6 @@ int XboxkrnlModule::LaunchModule(const char* path) {
|
||||||
// Set as the main module, while running.
|
// Set as the main module, while running.
|
||||||
kernel_state_->SetExecutableModule(module);
|
kernel_state_->SetExecutableModule(module);
|
||||||
|
|
||||||
// Waits for a debugger client, if desired.
|
|
||||||
if (emulator()->debugger()) {
|
|
||||||
emulator()->debugger()->PreLaunch();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Launch the module.
|
// Launch the module.
|
||||||
// NOTE: this won't return until the module exits.
|
// NOTE: this won't return until the module exits.
|
||||||
X_STATUS result_code = module->Launch(0);
|
X_STATUS result_code = module->Launch(0);
|
||||||
|
|
Loading…
Reference in New Issue