diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index c73a78eab..19dff73d7 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -82,3 +82,31 @@ void KernelState::SetExecutableModule(XModule* module) { executable_module_->Retain(); } } + +void KernelState::RegisterThread(XThread* thread) { + xe_mutex_lock(object_mutex_); + threads_by_id_[thread->thread_id()] = thread; + xe_mutex_unlock(object_mutex_); +} + +void KernelState::UnregisterThread(XThread* thread) { + xe_mutex_lock(object_mutex_); + auto it = threads_by_id_.find(thread->thread_id()); + if (it != threads_by_id_.end()) { + threads_by_id_.erase(it); + } + xe_mutex_unlock(object_mutex_); +} + +XThread* KernelState::GetThreadByID(uint32_t thread_id) { + XThread* thread = NULL; + xe_mutex_lock(object_mutex_); + auto it = threads_by_id_.find(thread_id); + if (it != threads_by_id_.end()) { + thread = it->second; + // Caller must release. + thread->Retain(); + } + xe_mutex_unlock(object_mutex_); + return thread; +} diff --git a/src/xenia/kernel/kernel_state.h b/src/xenia/kernel/kernel_state.h index ebca4c0a0..663cdd5f0 100644 --- a/src/xenia/kernel/kernel_state.h +++ b/src/xenia/kernel/kernel_state.h @@ -22,6 +22,7 @@ XEDECLARECLASS2(xe, cpu, Processor); XEDECLARECLASS2(xe, kernel, XModule); +XEDECLARECLASS2(xe, kernel, XThread); XEDECLARECLASS3(xe, kernel, fs, FileSystem); @@ -47,6 +48,10 @@ public: XModule* GetExecutableModule(); void SetExecutableModule(XModule* module); + void RegisterThread(XThread* thread); + void UnregisterThread(XThread* thread); + XThread* GetThreadByID(uint32_t thread_id); + private: Emulator* emulator_; Memory* memory_; @@ -55,6 +60,7 @@ private: ObjectTable* object_table_; xe_mutex_t* object_mutex_; + std::unordered_map threads_by_id_; XModule* executable_module_; diff --git a/src/xenia/kernel/objects/xthread.cc b/src/xenia/kernel/objects/xthread.cc index e5e36fe1c..afbec952b 100644 --- a/src/xenia/kernel/objects/xthread.cc +++ b/src/xenia/kernel/objects/xthread.cc @@ -40,6 +40,7 @@ XThread::XThread(KernelState* kernel_state, thread_state_address_(0), thread_state_(0), event_(NULL), + name_(0), irql_(0) { creation_params_.stack_size = stack_size; creation_params_.xapi_thread_startup = xapi_thread_startup; @@ -54,9 +55,15 @@ XThread::XThread(KernelState* kernel_state, event_ = new XEvent(kernel_state); event_->Initialize(true, false); + + // The kernel does not take a reference. We must unregister in the dtor. + kernel_state_->RegisterThread(this); } XThread::~XThread() { + // Unregister first to prevent lookups while deleting. + kernel_state_->UnregisterThread(this); + event_->Release(); PlatformDestroy(); @@ -70,6 +77,9 @@ XThread::~XThread() { if (thread_state_address_) { kernel_state()->memory()->HeapFree(thread_state_address_, 0); } + if (name_) { + xe_free(name_); + } if (thread_handle_) { // TODO(benvanik): platform kill @@ -121,6 +131,37 @@ void XThread::set_last_error(uint32_t error_code) { XESETUINT32BE(p + 0x160, error_code); } +void XThread::set_name(const char* name) { + if (name == name_) { + return; + } + if (name_) { + xe_free(name_); + } + name_ = xestrdupa(name); + +#if XE_PLATFORM(WIN32) + // Do the nasty set for us. + #pragma pack(push, 8) + typedef struct tagTHREADNAME_INFO { + DWORD dwType; // must be 0x1000 + LPCSTR szName; // pointer to name (in user addr space) + DWORD dwThreadID; // thread ID (-1=caller thread) + DWORD dwFlags; // reserved for future use, must be zero + } THREADNAME_INFO; + #pragma pack(pop) + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = name_; + info.dwThreadID = ::GetThreadId(thread_handle_); + info.dwFlags = 0; + __try { + RaiseException(0x406D1388, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } __except(EXCEPTION_CONTINUE_EXECUTION) { + } +#endif // WIN32 +} + X_STATUS XThread::Create() { // Allocate thread state block from heap. // This is set as r13 for user code and some special inlined Win32 calls diff --git a/src/xenia/kernel/objects/xthread.h b/src/xenia/kernel/objects/xthread.h index 029001d33..e1171c935 100644 --- a/src/xenia/kernel/objects/xthread.h +++ b/src/xenia/kernel/objects/xthread.h @@ -46,6 +46,8 @@ public: uint32_t thread_id(); uint32_t last_error(); void set_last_error(uint32_t error_code); + const char* name() const { return name_; } + void set_name(const char* name); X_STATUS Create(); X_STATUS Exit(int exit_code); @@ -83,6 +85,8 @@ private: uint32_t thread_state_address_; cpu::XenonThreadState* thread_state_; + char* name_; + uint32_t irql_; XEvent* event_; diff --git a/src/xenia/kernel/xboxkrnl_debug.cc b/src/xenia/kernel/xboxkrnl_debug.cc index a13eac5c8..975fdb169 100644 --- a/src/xenia/kernel/xboxkrnl_debug.cc +++ b/src/xenia/kernel/xboxkrnl_debug.cc @@ -241,6 +241,20 @@ SHIM_CALL DbgBreakPoint_shim( } +SHIM_CALL RtlRaiseException_shim( + PPCContext* ppc_state, KernelState* state) { + uint32_t record_ptr = SHIM_GET_ARG_32(0); + + uint32_t code = SHIM_MEM_32(record_ptr + 0); + + XELOGD( + "RtlRaiseException(%.8X(%.8X))", + record_ptr, code); + + XEASSERTALWAYS(); +} + + } // namespace kernel } // namespace xe @@ -249,4 +263,5 @@ void xe::kernel::xboxkrnl::RegisterDebugExports( ExportResolver* export_resolver, KernelState* state) { SHIM_SET_MAPPING("xboxkrnl.exe", DbgPrint, state); SHIM_SET_MAPPING("xboxkrnl.exe", DbgBreakPoint, state); + SHIM_SET_MAPPING("xboxkrnl.exe", RtlRaiseException, state); }