Moving threads to XHostThread and making shutdown not crash.

This commit is contained in:
Ben Vanik 2015-05-19 22:20:49 -07:00
parent 7a82ad839a
commit f88bf33b4f
22 changed files with 175 additions and 138 deletions

View file

@ -14,8 +14,8 @@
#include "xenia/base/math.h" #include "xenia/base/math.h"
#include "xenia/cpu/processor.h" #include "xenia/cpu/processor.h"
#include "xenia/cpu/thread_state.h" #include "xenia/cpu/thread_state.h"
#include "xenia/kernel/objects/xthread.h"
#include "xenia/emulator.h" #include "xenia/emulator.h"
#include "xenia/kernel/objects/xthread.h"
#include "xenia/profiling.h" #include "xenia/profiling.h"
// As with normal Microsoft, there are like twelve different ways to access // As with normal Microsoft, there are like twelve different ways to access
@ -48,7 +48,6 @@ namespace xe {
namespace apu { namespace apu {
using namespace xe::cpu; using namespace xe::cpu;
using namespace xe::kernel;
// Size of a hardware XMA context. // Size of a hardware XMA context.
const uint32_t kXmaContextSize = 64; const uint32_t kXmaContextSize = 64;
@ -56,7 +55,7 @@ const uint32_t kXmaContextSize = 64;
const uint32_t kXmaContextCount = 320; const uint32_t kXmaContextCount = 320;
AudioSystem::AudioSystem(Emulator* emulator) AudioSystem::AudioSystem(Emulator* emulator)
: emulator_(emulator), memory_(emulator->memory()), running_(false) { : emulator_(emulator), memory_(emulator->memory()), worker_running_(false) {
memset(clients_, 0, sizeof(clients_)); memset(clients_, 0, sizeof(clients_));
for (size_t i = 0; i < maximum_client_count_; ++i) { for (size_t i = 0; i < maximum_client_count_; ++i) {
unused_clients_.push(i); unused_clients_.push(i);
@ -91,22 +90,18 @@ X_STATUS AudioSystem::Setup() {
} }
registers_.next_context = 1; registers_.next_context = 1;
// Setup our worker thread worker_running_ = true;
std::function<int()> thread_fn = [this]() { worker_thread_ = new kernel::XHostThread(emulator()->kernel_state(),
this->ThreadStart(); 128 * 1024, 0, [this]() {
this->WorkerThreadMain();
return 0; return 0;
}; });
worker_thread_->Create();
running_ = true;
thread_ = std::make_unique<XHostThread>(emulator()->kernel_state(),
128 * 1024, 0, thread_fn);
thread_->Create();
return X_STATUS_SUCCESS; return X_STATUS_SUCCESS;
} }
void AudioSystem::ThreadStart() { void AudioSystem::WorkerThreadMain() {
xe::threading::set_name("Audio Worker"); xe::threading::set_name("Audio Worker");
// Initialize driver and ringbuffer. // Initialize driver and ringbuffer.
@ -115,7 +110,7 @@ void AudioSystem::ThreadStart() {
auto processor = emulator_->processor(); auto processor = emulator_->processor();
// Main run loop. // Main run loop.
while (running_) { while (worker_running_) {
auto result = auto result =
WaitForMultipleObjectsEx(DWORD(xe::countof(client_wait_handles_)), WaitForMultipleObjectsEx(DWORD(xe::countof(client_wait_handles_)),
client_wait_handles_, FALSE, INFINITE, FALSE); client_wait_handles_, FALSE, INFINITE, FALSE);
@ -135,8 +130,8 @@ void AudioSystem::ThreadStart() {
lock_.unlock(); lock_.unlock();
if (client_callback) { if (client_callback) {
uint64_t args[] = {client_callback_arg}; uint64_t args[] = {client_callback_arg};
processor->Execute(thread_->thread_state(), client_callback, args, processor->Execute(worker_thread_->thread_state(), client_callback,
xe::countof(args)); args, xe::countof(args));
} }
pumped++; pumped++;
index++; index++;
@ -145,7 +140,7 @@ void AudioSystem::ThreadStart() {
WAIT_OBJECT_0); WAIT_OBJECT_0);
} }
if (!running_) { if (!worker_running_) {
break; break;
} }
@ -154,7 +149,7 @@ void AudioSystem::ThreadStart() {
Sleep(500); Sleep(500);
} }
} }
running_ = false; worker_running_ = false;
// TODO(benvanik): call module API to kill? // TODO(benvanik): call module API to kill?
} }
@ -162,9 +157,10 @@ void AudioSystem::ThreadStart() {
void AudioSystem::Initialize() {} void AudioSystem::Initialize() {}
void AudioSystem::Shutdown() { void AudioSystem::Shutdown() {
running_ = false; worker_running_ = false;
ResetEvent(client_wait_handles_[maximum_client_count_]); SetEvent(client_wait_handles_[maximum_client_count_]);
thread_->Wait(0, 0, 0, NULL); worker_thread_->Wait(0, 0, 0, nullptr);
worker_thread_->Release();
memory()->SystemHeapFree(registers_.xma_context_array_ptr); memory()->SystemHeapFree(registers_.xma_context_array_ptr);
} }

View file

@ -13,15 +13,17 @@
#include <atomic> #include <atomic>
#include <mutex> #include <mutex>
#include <queue> #include <queue>
#include <thread>
#include "xenia/emulator.h" #include "xenia/emulator.h"
#include "xenia/xbox.h" #include "xenia/xbox.h"
namespace xe { namespace xe {
namespace kernel {
class XHostThread;
} // namespace kernel
} // namespace xe
namespace kernel { class XHostThread; } namespace xe {
namespace apu { namespace apu {
class AudioDriver; class AudioDriver;
@ -59,7 +61,7 @@ class AudioSystem {
virtual void Initialize(); virtual void Initialize();
private: private:
void ThreadStart(); void WorkerThreadMain();
static uint64_t MMIOReadRegisterThunk(AudioSystem* as, uint32_t addr) { static uint64_t MMIOReadRegisterThunk(AudioSystem* as, uint32_t addr) {
return as->ReadRegister(addr); return as->ReadRegister(addr);
@ -76,8 +78,8 @@ class AudioSystem {
Memory* memory_; Memory* memory_;
cpu::Processor* processor_; cpu::Processor* processor_;
std::unique_ptr<kernel::XHostThread> thread_; std::atomic<bool> worker_running_;
std::atomic<bool> running_; kernel::XHostThread* worker_thread_;
std::mutex lock_; std::mutex lock_;

View file

@ -28,7 +28,6 @@ using namespace xe::apu;
using namespace xe::cpu; using namespace xe::cpu;
using namespace xe::gpu; using namespace xe::gpu;
using namespace xe::hid; using namespace xe::hid;
using namespace xe::kernel;
using namespace xe::kernel::fs; using namespace xe::kernel::fs;
using namespace xe::ui; using namespace xe::ui;
@ -38,17 +37,14 @@ Emulator::Emulator(const std::wstring& command_line)
Emulator::~Emulator() { Emulator::~Emulator() {
// Note that we delete things in the reverse order they were initialized. // 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. // Give the systems time to shutdown before we delete them.
graphics_system_->Shutdown(); graphics_system_->Shutdown();
audio_system_->Shutdown(); audio_system_->Shutdown();
kernel_state_.reset();
file_system_.reset();
input_system_.reset();
graphics_system_.reset(); graphics_system_.reset();
audio_system_.reset(); audio_system_.reset();
@ -95,7 +91,7 @@ X_STATUS Emulator::Setup() {
} }
// Initialize the GPU. // Initialize the GPU.
graphics_system_ = std::move(xe::gpu::Create()); graphics_system_ = std::move(xe::gpu::Create(this));
if (!graphics_system_) { if (!graphics_system_) {
return X_STATUS_NOT_IMPLEMENTED; return X_STATUS_NOT_IMPLEMENTED;
} }
@ -106,15 +102,6 @@ X_STATUS Emulator::Setup() {
return X_STATUS_NOT_IMPLEMENTED; 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(); result = input_system_->Setup();
if (result) { if (result) {
return result; return result;
@ -124,7 +111,17 @@ X_STATUS Emulator::Setup() {
file_system_ = std::make_unique<FileSystem>(); file_system_ = std::make_unique<FileSystem>();
// Shared kernel state. // 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(); result = audio_system_->Setup();
if (result) { if (result) {
@ -132,8 +129,8 @@ X_STATUS Emulator::Setup() {
} }
// HLE kernel modules. // HLE kernel modules.
xboxkrnl_ = std::make_unique<XboxkrnlModule>(this, kernel_state_.get()); kernel_state_->LoadKernelModule<kernel::XboxkrnlModule>();
xam_ = std::make_unique<XamModule>(this, kernel_state_.get()); kernel_state_->LoadKernelModule<kernel::XamModule>();
return result; return result;
} }
@ -192,7 +189,15 @@ X_STATUS Emulator::LaunchSTFSTitle(const std::wstring& path) {
X_STATUS Emulator::CompleteLaunch(const std::wstring& path, X_STATUS Emulator::CompleteLaunch(const std::wstring& path,
const std::string& module_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 } // namespace xe

View file

@ -32,10 +32,6 @@ class GraphicsSystem;
namespace hid { namespace hid {
class InputSystem; class InputSystem;
} // namespace hid } // namespace hid
namespace kernel {
class XamModule;
class XboxkrnlModule;
} // namespace kernel
namespace ui { namespace ui {
class MainWindow; class MainWindow;
} // namespace ui } // namespace ui
@ -68,9 +64,6 @@ class Emulator {
kernel::KernelState* kernel_state() const { return kernel_state_.get(); } 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(); X_STATUS Setup();
// TODO(benvanik): raw binary. // TODO(benvanik): raw binary.
@ -97,8 +90,6 @@ class Emulator {
std::unique_ptr<kernel::fs::FileSystem> file_system_; std::unique_ptr<kernel::fs::FileSystem> file_system_;
std::unique_ptr<kernel::KernelState> kernel_state_; std::unique_ptr<kernel::KernelState> kernel_state_;
std::unique_ptr<kernel::XamModule> xam_;
std::unique_ptr<kernel::XboxkrnlModule> xboxkrnl_;
}; };
} // namespace xe } // namespace xe

View file

@ -19,6 +19,8 @@
#include "xenia/gpu/sampler_info.h" #include "xenia/gpu/sampler_info.h"
#include "xenia/gpu/texture_info.h" #include "xenia/gpu/texture_info.h"
#include "xenia/gpu/xenos.h" #include "xenia/gpu/xenos.h"
#include "xenia/emulator.h"
#include "xenia/kernel/objects/xthread.h"
#include "xenia/profiling.h" #include "xenia/profiling.h"
#include "third_party/xxhash/xxhash.h" #include "third_party/xxhash/xxhash.h"
@ -99,12 +101,12 @@ bool CommandProcessor::Initialize(std::unique_ptr<GLContext> context) {
context_ = std::move(context); context_ = std::move(context);
worker_running_ = true; worker_running_ = true;
worker_thread_ = std::thread([this]() { worker_thread_ = new kernel::XHostThread(
xe::threading::set_name("GL4 Worker"); graphics_system_->emulator()->kernel_state(), 128 * 1024, 0, [this]() {
xe::Profiler::ThreadEnter("GL4 Worker"); WorkerThreadMain();
WorkerMain(); return 0;
xe::Profiler::ThreadExit(); });
}); worker_thread_->Create();
return true; return true;
} }
@ -114,7 +116,8 @@ void CommandProcessor::Shutdown() {
worker_running_ = false; worker_running_ = false;
SetEvent(write_ptr_index_event_); SetEvent(write_ptr_index_event_);
worker_thread_.join(); worker_thread_->Wait(0, 0, 0, nullptr);
worker_thread_->Release();
all_pipelines_.clear(); all_pipelines_.clear();
all_shaders_.clear(); all_shaders_.clear();
@ -160,14 +163,16 @@ void CommandProcessor::EndTracing() {
void CommandProcessor::CallInThread(std::function<void()> fn) { void CommandProcessor::CallInThread(std::function<void()> fn) {
if (pending_fns_.empty() && if (pending_fns_.empty() &&
worker_thread_.get_id() == std::this_thread::get_id()) { worker_thread_ == kernel::XThread::GetCurrentThread()) {
fn(); fn();
} else { } else {
pending_fns_.push(std::move(fn)); pending_fns_.push(std::move(fn));
} }
} }
void CommandProcessor::WorkerMain() { void CommandProcessor::WorkerThreadMain() {
xe::threading::set_name("GL4 Worker");
context_->MakeCurrent(); context_->MakeCurrent();
if (!SetupGL()) { if (!SetupGL()) {
XEFATAL("Unable to setup command processor GL state"); XEFATAL("Unable to setup command processor GL state");

View file

@ -14,7 +14,6 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <queue> #include <queue>
#include <thread>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
@ -28,6 +27,12 @@
#include "xenia/gpu/xenos.h" #include "xenia/gpu/xenos.h"
#include "xenia/memory.h" #include "xenia/memory.h"
namespace xe {
namespace kernel {
class XHostThread;
} // namespace kernel
} // namespace xe
namespace xe { namespace xe {
namespace gpu { namespace gpu {
namespace gl4 { namespace gl4 {
@ -134,7 +139,7 @@ class CommandProcessor {
} handles; } handles;
}; };
void WorkerMain(); void WorkerThreadMain();
bool SetupGL(); bool SetupGL();
void ShutdownGL(); void ShutdownGL();
GLuint CreateGeometryProgram(const std::string& source); GLuint CreateGeometryProgram(const std::string& source);
@ -226,8 +231,9 @@ class CommandProcessor {
TraceState trace_state_; TraceState trace_state_;
std::wstring trace_frame_path_; std::wstring trace_frame_path_;
std::thread worker_thread_;
std::atomic<bool> worker_running_; std::atomic<bool> worker_running_;
kernel::XHostThread* worker_thread_;
std::unique_ptr<GLContext> context_; std::unique_ptr<GLContext> context_;
SwapHandler swap_handler_; SwapHandler swap_handler_;
std::queue<std::function<void()>> pending_fns_; std::queue<std::function<void()>> pending_fns_;

View file

@ -47,9 +47,9 @@ void InitializeIfNeeded() {
void CleanupOnShutdown() {} void CleanupOnShutdown() {}
std::unique_ptr<GraphicsSystem> Create() { std::unique_ptr<GraphicsSystem> Create(Emulator* emulator) {
InitializeIfNeeded(); InitializeIfNeeded();
return std::make_unique<GL4GraphicsSystem>(); return std::make_unique<GL4GraphicsSystem>(emulator);
} }
} // namespace gl4 } // namespace gl4

View file

@ -18,7 +18,7 @@ namespace xe {
namespace gpu { namespace gpu {
namespace gl4 { namespace gl4 {
std::unique_ptr<GraphicsSystem> Create(); std::unique_ptr<GraphicsSystem> Create(Emulator* emulator);
} // namespace gl4 } // namespace gl4
} // namespace gpu } // namespace gpu

View file

@ -23,8 +23,8 @@ namespace gl4 {
extern "C" GLEWContext* glewGetContext(); extern "C" GLEWContext* glewGetContext();
GL4GraphicsSystem::GL4GraphicsSystem() GL4GraphicsSystem::GL4GraphicsSystem(Emulator* emulator)
: GraphicsSystem(), timer_queue_(nullptr), vsync_timer_(nullptr) {} : GraphicsSystem(emulator), timer_queue_(nullptr), vsync_timer_(nullptr) {}
GL4GraphicsSystem::~GL4GraphicsSystem() = default; GL4GraphicsSystem::~GL4GraphicsSystem() = default;

View file

@ -23,7 +23,7 @@ namespace gl4 {
class GL4GraphicsSystem : public GraphicsSystem { class GL4GraphicsSystem : public GraphicsSystem {
public: public:
GL4GraphicsSystem(); GL4GraphicsSystem(Emulator* emulator);
~GL4GraphicsSystem() override; ~GL4GraphicsSystem() override;
X_STATUS Setup(cpu::Processor* processor, ui::PlatformLoop* target_loop, X_STATUS Setup(cpu::Processor* processor, ui::PlatformLoop* target_loop,

View file

@ -27,14 +27,14 @@ DEFINE_bool(vsync, true, "Enable VSYNC.");
namespace xe { namespace xe {
namespace gpu { namespace gpu {
std::unique_ptr<GraphicsSystem> Create() { std::unique_ptr<GraphicsSystem> Create(Emulator* emulator) {
if (FLAGS_gpu.compare("gl4") == 0) { if (FLAGS_gpu.compare("gl4") == 0) {
return xe::gpu::gl4::Create(); return xe::gpu::gl4::Create(emulator);
} else { } else {
// Create best available. // Create best available.
std::unique_ptr<GraphicsSystem> best; std::unique_ptr<GraphicsSystem> best;
best = xe::gpu::gl4::Create(); best = xe::gpu::gl4::Create(emulator);
if (best) { if (best) {
return best; return best;
} }

View file

@ -21,9 +21,7 @@ class Emulator;
namespace xe { namespace xe {
namespace gpu { namespace gpu {
std::unique_ptr<GraphicsSystem> Create(); std::unique_ptr<GraphicsSystem> Create(Emulator* emulator);
std::unique_ptr<GraphicsSystem> CreateGL4();
} // namespace gpu } // namespace gpu
} // namespace xe } // namespace xe

View file

@ -17,8 +17,9 @@
namespace xe { namespace xe {
namespace gpu { namespace gpu {
GraphicsSystem::GraphicsSystem() GraphicsSystem::GraphicsSystem(Emulator* emulator)
: memory_(nullptr), : emulator_(emulator),
memory_(nullptr),
processor_(nullptr), processor_(nullptr),
target_loop_(nullptr), target_loop_(nullptr),
target_window_(nullptr), target_window_(nullptr),

View file

@ -25,6 +25,7 @@ class GraphicsSystem {
public: public:
virtual ~GraphicsSystem(); virtual ~GraphicsSystem();
Emulator* emulator() const { return emulator_; }
Memory* memory() const { return memory_; } Memory* memory() const { return memory_; }
cpu::Processor* processor() const { return processor_; } cpu::Processor* processor() const { return processor_; }
@ -54,8 +55,9 @@ class GraphicsSystem {
virtual void ClearCaches() {} virtual void ClearCaches() {}
protected: protected:
GraphicsSystem(); GraphicsSystem(Emulator* emulator);
Emulator* emulator_;
Memory* memory_; Memory* memory_;
cpu::Processor* processor_; cpu::Processor* processor_;
ui::PlatformLoop* target_loop_; ui::PlatformLoop* target_loop_;

View file

@ -70,6 +70,15 @@ KernelState::KernelState(Emulator* emulator)
KernelState::~KernelState() { KernelState::~KernelState() {
SetExecutableModule(nullptr); 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 all objects.
delete object_table_; delete object_table_;
@ -80,10 +89,6 @@ KernelState::~KernelState() {
assert_true(shared_kernel_state_ == this); assert_true(shared_kernel_state_ == this);
shared_kernel_state_ = nullptr; shared_kernel_state_ = nullptr;
for (XUserModule* mod : user_modules_) {
mod->Release();
}
} }
KernelState* KernelState::shared() { return shared_kernel_state_; } KernelState* KernelState::shared() { return shared_kernel_state_; }
@ -99,14 +104,15 @@ void KernelState::UnregisterModule(XModule* module) {}
bool KernelState::IsKernelModule(const char* name) { bool KernelState::IsKernelModule(const char* name) {
if (!name) { if (!name) {
// executing module isn't a kernel module // Executing module isn't a kernel module.
return false; 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; return false;
} }
@ -115,32 +121,24 @@ XModule* KernelState::GetModule(const char* name) {
// NULL name = self. // NULL name = self.
// TODO(benvanik): lookup module from caller address. // TODO(benvanik): lookup module from caller address.
return GetExecutableModule(); 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) { } else if (strcasecmp(name, "kernel32.dll") == 0) {
// Some games request this, for some reason. wtf. // 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; 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() { 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) { XUserModule* KernelState::LoadUserModule(const char* raw_name) {
// Some games try to load relative to launch module, others specify full path. // Some games try to load relative to launch module, others specify full path.
std::string name = xe::find_name_from_path(raw_name); std::string name = xe::find_name_from_path(raw_name);

View file

@ -37,6 +37,7 @@ namespace xe {
namespace kernel { namespace kernel {
class Dispatcher; class Dispatcher;
class XKernelModule;
class XModule; class XModule;
class XNotifyListener; class XNotifyListener;
class XThread; class XThread;
@ -74,7 +75,13 @@ class KernelState {
XModule* GetModule(const char* name); XModule* GetModule(const char* name);
XUserModule* GetExecutableModule(); XUserModule* GetExecutableModule();
void SetExecutableModule(XUserModule* module); 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 RegisterThread(XThread* thread);
void UnregisterThread(XThread* thread); void UnregisterThread(XThread* thread);
@ -94,6 +101,8 @@ class KernelState {
uint32_t extended_error, uint32_t length); uint32_t extended_error, uint32_t length);
private: private:
void LoadKernelModule(XKernelModule* kernel_module);
Emulator* emulator_; Emulator* emulator_;
Memory* memory_; Memory* memory_;
cpu::Processor* processor_; cpu::Processor* processor_;
@ -113,7 +122,7 @@ class KernelState {
uint32_t process_type_; uint32_t process_type_;
XUserModule* executable_module_; XUserModule* executable_module_;
std::vector<XKernelModule*> kernel_modules_;
std::vector<XUserModule*> user_modules_; std::vector<XUserModule*> user_modules_;
friend class XObject; friend class XObject;

View file

@ -9,6 +9,8 @@
#include "xenia/kernel/objects/xmodule.h" #include "xenia/kernel/objects/xmodule.h"
#include "xenia/base/string.h"
namespace xe { namespace xe {
namespace kernel { namespace kernel {
@ -31,6 +33,19 @@ XModule::XModule(KernelState* kernel_state, const std::string& path)
XModule::~XModule() { kernel_state_->UnregisterModule(this); } 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); } void XModule::OnLoad() { kernel_state_->RegisterModule(this); }
X_STATUS XModule::GetSection(const char* name, uint32_t* out_section_data, X_STATUS XModule::GetSection(const char* name, uint32_t* out_section_data,

View file

@ -25,6 +25,7 @@ class XModule : public XObject {
const std::string& path() const { return path_; } const std::string& path() const { return path_; }
const std::string& name() const { return name_; } 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 GetProcAddressByOrdinal(uint16_t ordinal) = 0;
virtual uint32_t GetProcAddressByName(const char* name) = 0; virtual uint32_t GetProcAddressByName(const char* name) = 0;

View file

@ -156,7 +156,7 @@ X_STATUS XThread::Create() {
scratch_address_ = memory()->SystemHeapAlloc(scratch_size_); scratch_address_ = memory()->SystemHeapAlloc(scratch_size_);
// Allocate TLS block. // 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()) { if (module && module->xex_header()) {
const xe_xex2_header_t* header = module->xex_header(); const xe_xex2_header_t* header = module->xex_header();
tls_size = header->tls_info.slot_count * header->tls_info.data_size; tls_size = header->tls_info.slot_count * header->tls_info.data_size;
@ -194,15 +194,15 @@ X_STATUS XThread::Create() {
thread_state_->stack_base()); thread_state_->stack_base());
uint8_t* pcr = memory()->TranslateVirtual(pcr_address_); 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 + 0x000, tls_address_);
xe::store_and_swap<uint32_t>(pcr + 0x030, pcr_address_); xe::store_and_swap<uint32_t>(pcr + 0x030, pcr_address_);
xe::store_and_swap<uint32_t>(pcr + 0x070, thread_state_->stack_address() + xe::store_and_swap<uint32_t>(pcr + 0x070, thread_state_->stack_address() +
thread_state_->stack_size()); thread_state_->stack_size());
xe::store_and_swap<uint32_t>(pcr + 0x074, thread_state_->stack_address()); 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<uint32_t>(pcr + 0x100, thread_state_address_);
xe::store_and_swap<uint8_t> (pcr + 0x10C, 1); // Current CPU(?) 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<uint32_t>(pcr + 0x150, 0); // DPC active bool?
// Setup the thread state block (last error/etc). // Setup the thread state block (last error/etc).
uint8_t* p = memory()->TranslateVirtual(thread_state_address_); 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(); } void* XThread::GetWaitHandle() { return event_->GetWaitHandle(); }
XHostThread::XHostThread(KernelState* kernel_state, uint32_t stack_size, XHostThread::XHostThread(KernelState* kernel_state, uint32_t stack_size,
uint32_t creation_flags, std::function<int()> host_fn): uint32_t creation_flags, std::function<int()> host_fn)
XThread(kernel_state, stack_size, 0, 0, 0, creation_flags), : XThread(kernel_state, stack_size, 0, 0, 0, creation_flags),
host_fn_(host_fn) { host_fn_(host_fn) {}
}
void XHostThread::Execute() { void XHostThread::Execute() {
XELOGKERNEL("XThread::Execute thid %d (handle=%.8X, '%s', native=%.8X, <host>)", XELOGKERNEL(
thread_id_, handle(), name_.c_str(), "XThread::Execute thid %d (handle=%.8X, '%s', native=%.8X, <host>)",
xe::threading::current_thread_id()); thread_id_, handle(), name_.c_str(), xe::threading::current_thread_id());
// Let the kernel know we are starting. // Let the kernel know we are starting.
kernel_state()->OnThreadExecute(this); kernel_state()->OnThreadExecute(this);

View file

@ -354,7 +354,7 @@ void XUserModule::Dump() {
if (kernel_state_->IsKernelModule(library->name)) { if (kernel_state_->IsKernelModule(library->name)) {
KernelExport* kernel_export = KernelExport* kernel_export =
export_resolver->GetExportByOrdinal(library->name, info->ordinal); export_resolver->GetExportByOrdinal(library->name, info->ordinal);
if (kernel_export) { if (kernel_export) {
known_count++; known_count++;
if (kernel_export->is_implemented) { if (kernel_export->is_implemented) {
@ -371,7 +371,7 @@ void XUserModule::Dump() {
XModule* module = kernel_state_->GetModule(library->name); XModule* module = kernel_state_->GetModule(library->name);
if (module) { if (module) {
uint32_t export_addr = uint32_t export_addr =
module->GetProcAddressByOrdinal(info->ordinal); module->GetProcAddressByOrdinal(info->ordinal);
if (export_addr) { if (export_addr) {
impl_count++; impl_count++;
known_count++; known_count++;
@ -400,10 +400,10 @@ void XUserModule::Dump() {
const char* name = "UNKNOWN"; const char* name = "UNKNOWN";
bool implemented = false; bool implemented = false;
KernelExport* kernel_export; KernelExport* kernel_export = nullptr;
if (kernel_state_->IsKernelModule(library->name)) { if (kernel_state_->IsKernelModule(library->name)) {
kernel_export = kernel_export =
export_resolver->GetExportByOrdinal(library->name, info->ordinal); export_resolver->GetExportByOrdinal(library->name, info->ordinal);
if (kernel_export) { if (kernel_export) {
name = kernel_export->name; name = kernel_export->name;
implemented = kernel_export->is_implemented; implemented = kernel_export->is_implemented;

View file

@ -17,6 +17,7 @@ Win32Control::Win32Control(uint32_t flags) : Control(flags), hwnd_(nullptr) {}
Win32Control::~Win32Control() { Win32Control::~Win32Control() {
if (hwnd_) { if (hwnd_) {
SetWindowLongPtr(hwnd_, GWLP_USERDATA, 0);
CloseWindow(hwnd_); CloseWindow(hwnd_);
hwnd_ = nullptr; hwnd_ = nullptr;
} }

View file

@ -29,7 +29,7 @@ class PostedFn {
Win32Loop::Win32Loop() : thread_id_(0) { Win32Loop::Win32Loop() : thread_id_(0) {
xe::threading::Fence init_fence; xe::threading::Fence init_fence;
thread_ = std::thread([&]() { thread_ = std::thread([&init_fence, this]() {
xe::threading::set_name("Win32 Loop"); xe::threading::set_name("Win32 Loop");
thread_id_ = GetCurrentThreadId(); thread_id_ = GetCurrentThreadId();
@ -46,7 +46,10 @@ Win32Loop::Win32Loop() : thread_id_(0) {
init_fence.Wait(); init_fence.Wait();
} }
Win32Loop::~Win32Loop() = default; Win32Loop::~Win32Loop() {
Quit();
thread_.join();
}
void Win32Loop::ThreadMain() { void Win32Loop::ThreadMain() {
MSG msg; MSG msg;