Moving threads to XHostThread and making shutdown not crash.
This commit is contained in:
parent
7a82ad839a
commit
f88bf33b4f
|
@ -14,8 +14,8 @@
|
|||
#include "xenia/base/math.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/cpu/thread_state.h"
|
||||
#include "xenia/kernel/objects/xthread.h"
|
||||
#include "xenia/emulator.h"
|
||||
#include "xenia/kernel/objects/xthread.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
// As with normal Microsoft, there are like twelve different ways to access
|
||||
|
@ -48,7 +48,6 @@ namespace xe {
|
|||
namespace apu {
|
||||
|
||||
using namespace xe::cpu;
|
||||
using namespace xe::kernel;
|
||||
|
||||
// Size of a hardware XMA context.
|
||||
const uint32_t kXmaContextSize = 64;
|
||||
|
@ -56,7 +55,7 @@ const uint32_t kXmaContextSize = 64;
|
|||
const uint32_t kXmaContextCount = 320;
|
||||
|
||||
AudioSystem::AudioSystem(Emulator* emulator)
|
||||
: emulator_(emulator), memory_(emulator->memory()), running_(false) {
|
||||
: emulator_(emulator), memory_(emulator->memory()), worker_running_(false) {
|
||||
memset(clients_, 0, sizeof(clients_));
|
||||
for (size_t i = 0; i < maximum_client_count_; ++i) {
|
||||
unused_clients_.push(i);
|
||||
|
@ -91,22 +90,18 @@ X_STATUS AudioSystem::Setup() {
|
|||
}
|
||||
registers_.next_context = 1;
|
||||
|
||||
// Setup our worker thread
|
||||
std::function<int()> thread_fn = [this]() {
|
||||
this->ThreadStart();
|
||||
worker_running_ = true;
|
||||
worker_thread_ = new kernel::XHostThread(emulator()->kernel_state(),
|
||||
128 * 1024, 0, [this]() {
|
||||
this->WorkerThreadMain();
|
||||
return 0;
|
||||
};
|
||||
|
||||
running_ = true;
|
||||
|
||||
thread_ = std::make_unique<XHostThread>(emulator()->kernel_state(),
|
||||
128 * 1024, 0, thread_fn);
|
||||
thread_->Create();
|
||||
});
|
||||
worker_thread_->Create();
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void AudioSystem::ThreadStart() {
|
||||
void AudioSystem::WorkerThreadMain() {
|
||||
xe::threading::set_name("Audio Worker");
|
||||
|
||||
// Initialize driver and ringbuffer.
|
||||
|
@ -115,7 +110,7 @@ void AudioSystem::ThreadStart() {
|
|||
auto processor = emulator_->processor();
|
||||
|
||||
// Main run loop.
|
||||
while (running_) {
|
||||
while (worker_running_) {
|
||||
auto result =
|
||||
WaitForMultipleObjectsEx(DWORD(xe::countof(client_wait_handles_)),
|
||||
client_wait_handles_, FALSE, INFINITE, FALSE);
|
||||
|
@ -135,8 +130,8 @@ void AudioSystem::ThreadStart() {
|
|||
lock_.unlock();
|
||||
if (client_callback) {
|
||||
uint64_t args[] = {client_callback_arg};
|
||||
processor->Execute(thread_->thread_state(), client_callback, args,
|
||||
xe::countof(args));
|
||||
processor->Execute(worker_thread_->thread_state(), client_callback,
|
||||
args, xe::countof(args));
|
||||
}
|
||||
pumped++;
|
||||
index++;
|
||||
|
@ -145,7 +140,7 @@ void AudioSystem::ThreadStart() {
|
|||
WAIT_OBJECT_0);
|
||||
}
|
||||
|
||||
if (!running_) {
|
||||
if (!worker_running_) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -154,7 +149,7 @@ void AudioSystem::ThreadStart() {
|
|||
Sleep(500);
|
||||
}
|
||||
}
|
||||
running_ = false;
|
||||
worker_running_ = false;
|
||||
|
||||
// TODO(benvanik): call module API to kill?
|
||||
}
|
||||
|
@ -162,9 +157,10 @@ void AudioSystem::ThreadStart() {
|
|||
void AudioSystem::Initialize() {}
|
||||
|
||||
void AudioSystem::Shutdown() {
|
||||
running_ = false;
|
||||
ResetEvent(client_wait_handles_[maximum_client_count_]);
|
||||
thread_->Wait(0, 0, 0, NULL);
|
||||
worker_running_ = false;
|
||||
SetEvent(client_wait_handles_[maximum_client_count_]);
|
||||
worker_thread_->Wait(0, 0, 0, nullptr);
|
||||
worker_thread_->Release();
|
||||
|
||||
memory()->SystemHeapFree(registers_.xma_context_array_ptr);
|
||||
}
|
||||
|
|
|
@ -13,15 +13,17 @@
|
|||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
|
||||
#include "xenia/emulator.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
class XHostThread;
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
namespace kernel { class XHostThread; }
|
||||
|
||||
namespace xe {
|
||||
namespace apu {
|
||||
|
||||
class AudioDriver;
|
||||
|
@ -59,7 +61,7 @@ class AudioSystem {
|
|||
virtual void Initialize();
|
||||
|
||||
private:
|
||||
void ThreadStart();
|
||||
void WorkerThreadMain();
|
||||
|
||||
static uint64_t MMIOReadRegisterThunk(AudioSystem* as, uint32_t addr) {
|
||||
return as->ReadRegister(addr);
|
||||
|
@ -76,8 +78,8 @@ class AudioSystem {
|
|||
Memory* memory_;
|
||||
cpu::Processor* processor_;
|
||||
|
||||
std::unique_ptr<kernel::XHostThread> thread_;
|
||||
std::atomic<bool> running_;
|
||||
std::atomic<bool> worker_running_;
|
||||
kernel::XHostThread* worker_thread_;
|
||||
|
||||
std::mutex lock_;
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ using namespace xe::apu;
|
|||
using namespace xe::cpu;
|
||||
using namespace xe::gpu;
|
||||
using namespace xe::hid;
|
||||
using namespace xe::kernel;
|
||||
using namespace xe::kernel::fs;
|
||||
using namespace xe::ui;
|
||||
|
||||
|
@ -38,17 +37,14 @@ Emulator::Emulator(const std::wstring& command_line)
|
|||
Emulator::~Emulator() {
|
||||
// Note that we delete things in the reverse order they were initialized.
|
||||
|
||||
xam_.reset();
|
||||
xboxkrnl_.reset();
|
||||
kernel_state_.reset();
|
||||
|
||||
file_system_.reset();
|
||||
|
||||
input_system_.reset();
|
||||
|
||||
// Give the systems time to shutdown before we delete them.
|
||||
graphics_system_->Shutdown();
|
||||
audio_system_->Shutdown();
|
||||
|
||||
kernel_state_.reset();
|
||||
file_system_.reset();
|
||||
|
||||
input_system_.reset();
|
||||
graphics_system_.reset();
|
||||
audio_system_.reset();
|
||||
|
||||
|
@ -95,7 +91,7 @@ X_STATUS Emulator::Setup() {
|
|||
}
|
||||
|
||||
// Initialize the GPU.
|
||||
graphics_system_ = std::move(xe::gpu::Create());
|
||||
graphics_system_ = std::move(xe::gpu::Create(this));
|
||||
if (!graphics_system_) {
|
||||
return X_STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -106,15 +102,6 @@ X_STATUS Emulator::Setup() {
|
|||
return X_STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// Setup the core components.
|
||||
if (!processor_->Setup()) {
|
||||
return result;
|
||||
}
|
||||
result = graphics_system_->Setup(processor_.get(), main_window_->loop(),
|
||||
main_window_.get());
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
result = input_system_->Setup();
|
||||
if (result) {
|
||||
return result;
|
||||
|
@ -124,7 +111,17 @@ X_STATUS Emulator::Setup() {
|
|||
file_system_ = std::make_unique<FileSystem>();
|
||||
|
||||
// Shared kernel state.
|
||||
kernel_state_ = std::make_unique<KernelState>(this);
|
||||
kernel_state_ = std::make_unique<kernel::KernelState>(this);
|
||||
|
||||
// Setup the core components.
|
||||
if (!processor_->Setup()) {
|
||||
return result;
|
||||
}
|
||||
result = graphics_system_->Setup(processor_.get(), main_window_->loop(),
|
||||
main_window_.get());
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = audio_system_->Setup();
|
||||
if (result) {
|
||||
|
@ -132,8 +129,8 @@ X_STATUS Emulator::Setup() {
|
|||
}
|
||||
|
||||
// HLE kernel modules.
|
||||
xboxkrnl_ = std::make_unique<XboxkrnlModule>(this, kernel_state_.get());
|
||||
xam_ = std::make_unique<XamModule>(this, kernel_state_.get());
|
||||
kernel_state_->LoadKernelModule<kernel::XboxkrnlModule>();
|
||||
kernel_state_->LoadKernelModule<kernel::XamModule>();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -192,7 +189,15 @@ X_STATUS Emulator::LaunchSTFSTitle(const std::wstring& path) {
|
|||
|
||||
X_STATUS Emulator::CompleteLaunch(const std::wstring& path,
|
||||
const std::string& module_path) {
|
||||
return xboxkrnl_->LaunchModule(module_path.c_str());
|
||||
auto xboxkrnl = static_cast<kernel::XboxkrnlModule*>(
|
||||
kernel_state_->GetModule("xboxkrnl.exe"));
|
||||
int result = xboxkrnl->LaunchModule(module_path.c_str());
|
||||
xboxkrnl->Release();
|
||||
if (result == 0) {
|
||||
return X_STATUS_SUCCESS;
|
||||
} else {
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xe
|
||||
|
|
|
@ -32,10 +32,6 @@ class GraphicsSystem;
|
|||
namespace hid {
|
||||
class InputSystem;
|
||||
} // namespace hid
|
||||
namespace kernel {
|
||||
class XamModule;
|
||||
class XboxkrnlModule;
|
||||
} // namespace kernel
|
||||
namespace ui {
|
||||
class MainWindow;
|
||||
} // namespace ui
|
||||
|
@ -68,9 +64,6 @@ class Emulator {
|
|||
|
||||
kernel::KernelState* kernel_state() const { return kernel_state_.get(); }
|
||||
|
||||
kernel::XboxkrnlModule* xboxkrnl() const { return xboxkrnl_.get(); }
|
||||
kernel::XamModule* xam() const { return xam_.get(); }
|
||||
|
||||
X_STATUS Setup();
|
||||
|
||||
// TODO(benvanik): raw binary.
|
||||
|
@ -97,8 +90,6 @@ class Emulator {
|
|||
std::unique_ptr<kernel::fs::FileSystem> file_system_;
|
||||
|
||||
std::unique_ptr<kernel::KernelState> kernel_state_;
|
||||
std::unique_ptr<kernel::XamModule> xam_;
|
||||
std::unique_ptr<kernel::XboxkrnlModule> xboxkrnl_;
|
||||
};
|
||||
|
||||
} // namespace xe
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include "xenia/gpu/sampler_info.h"
|
||||
#include "xenia/gpu/texture_info.h"
|
||||
#include "xenia/gpu/xenos.h"
|
||||
#include "xenia/emulator.h"
|
||||
#include "xenia/kernel/objects/xthread.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
#include "third_party/xxhash/xxhash.h"
|
||||
|
@ -99,12 +101,12 @@ bool CommandProcessor::Initialize(std::unique_ptr<GLContext> context) {
|
|||
context_ = std::move(context);
|
||||
|
||||
worker_running_ = true;
|
||||
worker_thread_ = std::thread([this]() {
|
||||
xe::threading::set_name("GL4 Worker");
|
||||
xe::Profiler::ThreadEnter("GL4 Worker");
|
||||
WorkerMain();
|
||||
xe::Profiler::ThreadExit();
|
||||
});
|
||||
worker_thread_ = new kernel::XHostThread(
|
||||
graphics_system_->emulator()->kernel_state(), 128 * 1024, 0, [this]() {
|
||||
WorkerThreadMain();
|
||||
return 0;
|
||||
});
|
||||
worker_thread_->Create();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -114,7 +116,8 @@ void CommandProcessor::Shutdown() {
|
|||
|
||||
worker_running_ = false;
|
||||
SetEvent(write_ptr_index_event_);
|
||||
worker_thread_.join();
|
||||
worker_thread_->Wait(0, 0, 0, nullptr);
|
||||
worker_thread_->Release();
|
||||
|
||||
all_pipelines_.clear();
|
||||
all_shaders_.clear();
|
||||
|
@ -160,14 +163,16 @@ void CommandProcessor::EndTracing() {
|
|||
|
||||
void CommandProcessor::CallInThread(std::function<void()> fn) {
|
||||
if (pending_fns_.empty() &&
|
||||
worker_thread_.get_id() == std::this_thread::get_id()) {
|
||||
worker_thread_ == kernel::XThread::GetCurrentThread()) {
|
||||
fn();
|
||||
} else {
|
||||
pending_fns_.push(std::move(fn));
|
||||
}
|
||||
}
|
||||
|
||||
void CommandProcessor::WorkerMain() {
|
||||
void CommandProcessor::WorkerThreadMain() {
|
||||
xe::threading::set_name("GL4 Worker");
|
||||
|
||||
context_->MakeCurrent();
|
||||
if (!SetupGL()) {
|
||||
XEFATAL("Unable to setup command processor GL state");
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include <functional>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
|
@ -28,6 +27,12 @@
|
|||
#include "xenia/gpu/xenos.h"
|
||||
#include "xenia/memory.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
class XHostThread;
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
namespace gl4 {
|
||||
|
@ -134,7 +139,7 @@ class CommandProcessor {
|
|||
} handles;
|
||||
};
|
||||
|
||||
void WorkerMain();
|
||||
void WorkerThreadMain();
|
||||
bool SetupGL();
|
||||
void ShutdownGL();
|
||||
GLuint CreateGeometryProgram(const std::string& source);
|
||||
|
@ -226,8 +231,9 @@ class CommandProcessor {
|
|||
TraceState trace_state_;
|
||||
std::wstring trace_frame_path_;
|
||||
|
||||
std::thread worker_thread_;
|
||||
std::atomic<bool> worker_running_;
|
||||
kernel::XHostThread* worker_thread_;
|
||||
|
||||
std::unique_ptr<GLContext> context_;
|
||||
SwapHandler swap_handler_;
|
||||
std::queue<std::function<void()>> pending_fns_;
|
||||
|
|
|
@ -47,9 +47,9 @@ void InitializeIfNeeded() {
|
|||
|
||||
void CleanupOnShutdown() {}
|
||||
|
||||
std::unique_ptr<GraphicsSystem> Create() {
|
||||
std::unique_ptr<GraphicsSystem> Create(Emulator* emulator) {
|
||||
InitializeIfNeeded();
|
||||
return std::make_unique<GL4GraphicsSystem>();
|
||||
return std::make_unique<GL4GraphicsSystem>(emulator);
|
||||
}
|
||||
|
||||
} // namespace gl4
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace xe {
|
|||
namespace gpu {
|
||||
namespace gl4 {
|
||||
|
||||
std::unique_ptr<GraphicsSystem> Create();
|
||||
std::unique_ptr<GraphicsSystem> Create(Emulator* emulator);
|
||||
|
||||
} // namespace gl4
|
||||
} // namespace gpu
|
||||
|
|
|
@ -23,8 +23,8 @@ namespace gl4 {
|
|||
|
||||
extern "C" GLEWContext* glewGetContext();
|
||||
|
||||
GL4GraphicsSystem::GL4GraphicsSystem()
|
||||
: GraphicsSystem(), timer_queue_(nullptr), vsync_timer_(nullptr) {}
|
||||
GL4GraphicsSystem::GL4GraphicsSystem(Emulator* emulator)
|
||||
: GraphicsSystem(emulator), timer_queue_(nullptr), vsync_timer_(nullptr) {}
|
||||
|
||||
GL4GraphicsSystem::~GL4GraphicsSystem() = default;
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace gl4 {
|
|||
|
||||
class GL4GraphicsSystem : public GraphicsSystem {
|
||||
public:
|
||||
GL4GraphicsSystem();
|
||||
GL4GraphicsSystem(Emulator* emulator);
|
||||
~GL4GraphicsSystem() override;
|
||||
|
||||
X_STATUS Setup(cpu::Processor* processor, ui::PlatformLoop* target_loop,
|
||||
|
|
|
@ -27,14 +27,14 @@ DEFINE_bool(vsync, true, "Enable VSYNC.");
|
|||
namespace xe {
|
||||
namespace gpu {
|
||||
|
||||
std::unique_ptr<GraphicsSystem> Create() {
|
||||
std::unique_ptr<GraphicsSystem> Create(Emulator* emulator) {
|
||||
if (FLAGS_gpu.compare("gl4") == 0) {
|
||||
return xe::gpu::gl4::Create();
|
||||
return xe::gpu::gl4::Create(emulator);
|
||||
} else {
|
||||
// Create best available.
|
||||
std::unique_ptr<GraphicsSystem> best;
|
||||
|
||||
best = xe::gpu::gl4::Create();
|
||||
best = xe::gpu::gl4::Create(emulator);
|
||||
if (best) {
|
||||
return best;
|
||||
}
|
||||
|
|
|
@ -21,9 +21,7 @@ class Emulator;
|
|||
namespace xe {
|
||||
namespace gpu {
|
||||
|
||||
std::unique_ptr<GraphicsSystem> Create();
|
||||
|
||||
std::unique_ptr<GraphicsSystem> CreateGL4();
|
||||
std::unique_ptr<GraphicsSystem> Create(Emulator* emulator);
|
||||
|
||||
} // namespace gpu
|
||||
} // namespace xe
|
||||
|
|
|
@ -17,8 +17,9 @@
|
|||
namespace xe {
|
||||
namespace gpu {
|
||||
|
||||
GraphicsSystem::GraphicsSystem()
|
||||
: memory_(nullptr),
|
||||
GraphicsSystem::GraphicsSystem(Emulator* emulator)
|
||||
: emulator_(emulator),
|
||||
memory_(nullptr),
|
||||
processor_(nullptr),
|
||||
target_loop_(nullptr),
|
||||
target_window_(nullptr),
|
||||
|
|
|
@ -25,6 +25,7 @@ class GraphicsSystem {
|
|||
public:
|
||||
virtual ~GraphicsSystem();
|
||||
|
||||
Emulator* emulator() const { return emulator_; }
|
||||
Memory* memory() const { return memory_; }
|
||||
cpu::Processor* processor() const { return processor_; }
|
||||
|
||||
|
@ -54,8 +55,9 @@ class GraphicsSystem {
|
|||
virtual void ClearCaches() {}
|
||||
|
||||
protected:
|
||||
GraphicsSystem();
|
||||
GraphicsSystem(Emulator* emulator);
|
||||
|
||||
Emulator* emulator_;
|
||||
Memory* memory_;
|
||||
cpu::Processor* processor_;
|
||||
ui::PlatformLoop* target_loop_;
|
||||
|
|
|
@ -70,6 +70,15 @@ KernelState::KernelState(Emulator* emulator)
|
|||
KernelState::~KernelState() {
|
||||
SetExecutableModule(nullptr);
|
||||
|
||||
for (auto user_module : user_modules_) {
|
||||
user_module->Release();
|
||||
}
|
||||
user_modules_.clear();
|
||||
for (auto kernel_module : kernel_modules_) {
|
||||
kernel_module->Release();
|
||||
}
|
||||
kernel_modules_.clear();
|
||||
|
||||
// Delete all objects.
|
||||
delete object_table_;
|
||||
|
||||
|
@ -80,10 +89,6 @@ KernelState::~KernelState() {
|
|||
|
||||
assert_true(shared_kernel_state_ == this);
|
||||
shared_kernel_state_ = nullptr;
|
||||
|
||||
for (XUserModule* mod : user_modules_) {
|
||||
mod->Release();
|
||||
}
|
||||
}
|
||||
|
||||
KernelState* KernelState::shared() { return shared_kernel_state_; }
|
||||
|
@ -99,14 +104,15 @@ void KernelState::UnregisterModule(XModule* module) {}
|
|||
|
||||
bool KernelState::IsKernelModule(const char* name) {
|
||||
if (!name) {
|
||||
// executing module isn't a kernel module
|
||||
// Executing module isn't a kernel module.
|
||||
return false;
|
||||
} else if (strcasecmp(name, "xam.xex") == 0) {
|
||||
return true;
|
||||
} else if (strcasecmp(name, "xboxkrnl.exe") == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
|
||||
for (auto kernel_module : kernel_modules_) {
|
||||
if (kernel_module->Matches(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -115,32 +121,24 @@ XModule* KernelState::GetModule(const char* name) {
|
|||
// NULL name = self.
|
||||
// TODO(benvanik): lookup module from caller address.
|
||||
return GetExecutableModule();
|
||||
} else if (strcasecmp(name, "xam.xex") == 0) {
|
||||
auto module = emulator_->xam();
|
||||
module->Retain();
|
||||
return module;
|
||||
} else if (strcasecmp(name, "xboxkrnl.exe") == 0) {
|
||||
auto module = emulator_->xboxkrnl();
|
||||
module->Retain();
|
||||
return module;
|
||||
} else if (strcasecmp(name, "kernel32.dll") == 0) {
|
||||
// Some games request this, for some reason. wtf.
|
||||
return nullptr;
|
||||
} else {
|
||||
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
|
||||
|
||||
for (XUserModule* module : user_modules_) {
|
||||
if ((strcasecmp(xe::find_name_from_path(module->path()).c_str(), name) ==
|
||||
0) ||
|
||||
(strcasecmp(module->name().c_str(), name) == 0) ||
|
||||
(strcasecmp(module->path().c_str(), name) == 0)) {
|
||||
module->Retain();
|
||||
return module;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
|
||||
for (auto kernel_module : kernel_modules_) {
|
||||
if (kernel_module->Matches(name)) {
|
||||
kernel_module->Retain();
|
||||
return kernel_module;
|
||||
}
|
||||
}
|
||||
for (auto user_module : user_modules_) {
|
||||
if (user_module->Matches(name)) {
|
||||
user_module->Retain();
|
||||
return user_module;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
XUserModule* KernelState::GetExecutableModule() {
|
||||
|
@ -166,6 +164,11 @@ void KernelState::SetExecutableModule(XUserModule* module) {
|
|||
}
|
||||
}
|
||||
|
||||
void KernelState::LoadKernelModule(XKernelModule* kernel_module) {
|
||||
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
|
||||
kernel_modules_.push_back(kernel_module);
|
||||
}
|
||||
|
||||
XUserModule* KernelState::LoadUserModule(const char* raw_name) {
|
||||
// Some games try to load relative to launch module, others specify full path.
|
||||
std::string name = xe::find_name_from_path(raw_name);
|
||||
|
|
|
@ -37,6 +37,7 @@ namespace xe {
|
|||
namespace kernel {
|
||||
|
||||
class Dispatcher;
|
||||
class XKernelModule;
|
||||
class XModule;
|
||||
class XNotifyListener;
|
||||
class XThread;
|
||||
|
@ -74,7 +75,13 @@ class KernelState {
|
|||
XModule* GetModule(const char* name);
|
||||
XUserModule* GetExecutableModule();
|
||||
void SetExecutableModule(XUserModule* module);
|
||||
XUserModule* LoadUserModule(const char *name);
|
||||
template <typename T>
|
||||
XKernelModule* LoadKernelModule() {
|
||||
auto kernel_module = std::make_unique<T>(emulator_, this);
|
||||
LoadKernelModule(kernel_module.get());
|
||||
return kernel_module.release();
|
||||
}
|
||||
XUserModule* LoadUserModule(const char* name);
|
||||
|
||||
void RegisterThread(XThread* thread);
|
||||
void UnregisterThread(XThread* thread);
|
||||
|
@ -94,6 +101,8 @@ class KernelState {
|
|||
uint32_t extended_error, uint32_t length);
|
||||
|
||||
private:
|
||||
void LoadKernelModule(XKernelModule* kernel_module);
|
||||
|
||||
Emulator* emulator_;
|
||||
Memory* memory_;
|
||||
cpu::Processor* processor_;
|
||||
|
@ -113,7 +122,7 @@ class KernelState {
|
|||
|
||||
uint32_t process_type_;
|
||||
XUserModule* executable_module_;
|
||||
|
||||
std::vector<XKernelModule*> kernel_modules_;
|
||||
std::vector<XUserModule*> user_modules_;
|
||||
|
||||
friend class XObject;
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include "xenia/kernel/objects/xmodule.h"
|
||||
|
||||
#include "xenia/base/string.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
|
@ -31,6 +33,19 @@ XModule::XModule(KernelState* kernel_state, const std::string& path)
|
|||
|
||||
XModule::~XModule() { kernel_state_->UnregisterModule(this); }
|
||||
|
||||
bool XModule::Matches(const std::string& name) const {
|
||||
if (strcasecmp(xe::find_name_from_path(path_).c_str(), name.c_str()) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (strcasecmp(name_.c_str(), name.c_str()) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (strcasecmp(path_.c_str(), name.c_str()) == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void XModule::OnLoad() { kernel_state_->RegisterModule(this); }
|
||||
|
||||
X_STATUS XModule::GetSection(const char* name, uint32_t* out_section_data,
|
||||
|
|
|
@ -25,6 +25,7 @@ class XModule : public XObject {
|
|||
|
||||
const std::string& path() const { return path_; }
|
||||
const std::string& name() const { return name_; }
|
||||
bool Matches(const std::string& name) const;
|
||||
|
||||
virtual uint32_t GetProcAddressByOrdinal(uint16_t ordinal) = 0;
|
||||
virtual uint32_t GetProcAddressByName(const char* name) = 0;
|
||||
|
|
|
@ -156,7 +156,7 @@ X_STATUS XThread::Create() {
|
|||
scratch_address_ = memory()->SystemHeapAlloc(scratch_size_);
|
||||
|
||||
// Allocate TLS block.
|
||||
uint32_t tls_size = 32; // Default 32 (is this OK?)
|
||||
uint32_t tls_size = 32; // Default 32 (is this OK?)
|
||||
if (module && module->xex_header()) {
|
||||
const xe_xex2_header_t* header = module->xex_header();
|
||||
tls_size = header->tls_info.slot_count * header->tls_info.data_size;
|
||||
|
@ -194,15 +194,15 @@ X_STATUS XThread::Create() {
|
|||
thread_state_->stack_base());
|
||||
|
||||
uint8_t* pcr = memory()->TranslateVirtual(pcr_address_);
|
||||
std::memset(pcr, 0x0, 0x2D8 + 0xAB0); // Zero the PCR
|
||||
std::memset(pcr, 0x0, 0x2D8 + 0xAB0); // Zero the PCR
|
||||
xe::store_and_swap<uint32_t>(pcr + 0x000, tls_address_);
|
||||
xe::store_and_swap<uint32_t>(pcr + 0x030, pcr_address_);
|
||||
xe::store_and_swap<uint32_t>(pcr + 0x070, thread_state_->stack_address() +
|
||||
thread_state_->stack_size());
|
||||
xe::store_and_swap<uint32_t>(pcr + 0x074, thread_state_->stack_address());
|
||||
xe::store_and_swap<uint32_t>(pcr + 0x100, thread_state_address_);
|
||||
xe::store_and_swap<uint8_t> (pcr + 0x10C, 1); // Current CPU(?)
|
||||
xe::store_and_swap<uint32_t>(pcr + 0x150, 0); // DPC active bool?
|
||||
xe::store_and_swap<uint8_t>(pcr + 0x10C, 1); // Current CPU(?)
|
||||
xe::store_and_swap<uint32_t>(pcr + 0x150, 0); // DPC active bool?
|
||||
|
||||
// Setup the thread state block (last error/etc).
|
||||
uint8_t* p = memory()->TranslateVirtual(thread_state_address_);
|
||||
|
@ -622,15 +622,14 @@ X_STATUS XThread::Delay(uint32_t processor_mode, uint32_t alertable,
|
|||
void* XThread::GetWaitHandle() { return event_->GetWaitHandle(); }
|
||||
|
||||
XHostThread::XHostThread(KernelState* kernel_state, uint32_t stack_size,
|
||||
uint32_t creation_flags, std::function<int()> host_fn):
|
||||
XThread(kernel_state, stack_size, 0, 0, 0, creation_flags),
|
||||
host_fn_(host_fn) {
|
||||
}
|
||||
uint32_t creation_flags, std::function<int()> host_fn)
|
||||
: XThread(kernel_state, stack_size, 0, 0, 0, creation_flags),
|
||||
host_fn_(host_fn) {}
|
||||
|
||||
void XHostThread::Execute() {
|
||||
XELOGKERNEL("XThread::Execute thid %d (handle=%.8X, '%s', native=%.8X, <host>)",
|
||||
thread_id_, handle(), name_.c_str(),
|
||||
xe::threading::current_thread_id());
|
||||
XELOGKERNEL(
|
||||
"XThread::Execute thid %d (handle=%.8X, '%s', native=%.8X, <host>)",
|
||||
thread_id_, handle(), name_.c_str(), xe::threading::current_thread_id());
|
||||
|
||||
// Let the kernel know we are starting.
|
||||
kernel_state()->OnThreadExecute(this);
|
||||
|
|
|
@ -354,7 +354,7 @@ void XUserModule::Dump() {
|
|||
|
||||
if (kernel_state_->IsKernelModule(library->name)) {
|
||||
KernelExport* kernel_export =
|
||||
export_resolver->GetExportByOrdinal(library->name, info->ordinal);
|
||||
export_resolver->GetExportByOrdinal(library->name, info->ordinal);
|
||||
if (kernel_export) {
|
||||
known_count++;
|
||||
if (kernel_export->is_implemented) {
|
||||
|
@ -371,7 +371,7 @@ void XUserModule::Dump() {
|
|||
XModule* module = kernel_state_->GetModule(library->name);
|
||||
if (module) {
|
||||
uint32_t export_addr =
|
||||
module->GetProcAddressByOrdinal(info->ordinal);
|
||||
module->GetProcAddressByOrdinal(info->ordinal);
|
||||
if (export_addr) {
|
||||
impl_count++;
|
||||
known_count++;
|
||||
|
@ -400,10 +400,10 @@ void XUserModule::Dump() {
|
|||
const char* name = "UNKNOWN";
|
||||
bool implemented = false;
|
||||
|
||||
KernelExport* kernel_export;
|
||||
KernelExport* kernel_export = nullptr;
|
||||
if (kernel_state_->IsKernelModule(library->name)) {
|
||||
kernel_export =
|
||||
export_resolver->GetExportByOrdinal(library->name, info->ordinal);
|
||||
export_resolver->GetExportByOrdinal(library->name, info->ordinal);
|
||||
if (kernel_export) {
|
||||
name = kernel_export->name;
|
||||
implemented = kernel_export->is_implemented;
|
||||
|
|
|
@ -17,6 +17,7 @@ Win32Control::Win32Control(uint32_t flags) : Control(flags), hwnd_(nullptr) {}
|
|||
|
||||
Win32Control::~Win32Control() {
|
||||
if (hwnd_) {
|
||||
SetWindowLongPtr(hwnd_, GWLP_USERDATA, 0);
|
||||
CloseWindow(hwnd_);
|
||||
hwnd_ = nullptr;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ class PostedFn {
|
|||
|
||||
Win32Loop::Win32Loop() : thread_id_(0) {
|
||||
xe::threading::Fence init_fence;
|
||||
thread_ = std::thread([&]() {
|
||||
thread_ = std::thread([&init_fence, this]() {
|
||||
xe::threading::set_name("Win32 Loop");
|
||||
thread_id_ = GetCurrentThreadId();
|
||||
|
||||
|
@ -46,7 +46,10 @@ Win32Loop::Win32Loop() : thread_id_(0) {
|
|||
init_fence.Wait();
|
||||
}
|
||||
|
||||
Win32Loop::~Win32Loop() = default;
|
||||
Win32Loop::~Win32Loop() {
|
||||
Quit();
|
||||
thread_.join();
|
||||
}
|
||||
|
||||
void Win32Loop::ThreadMain() {
|
||||
MSG msg;
|
||||
|
|
Loading…
Reference in New Issue