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