Moving threads to XHostThread and making shutdown not crash.
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user