RAII object reference, debug mutex, etc.
This commit is contained in:
parent
e55be7d2c9
commit
8ac1f61c64
|
@ -224,6 +224,7 @@
|
||||||
<ClInclude Include="src\xenia\base\mapped_memory.h" />
|
<ClInclude Include="src\xenia\base\mapped_memory.h" />
|
||||||
<ClInclude Include="src\xenia\base\math.h" />
|
<ClInclude Include="src\xenia\base\math.h" />
|
||||||
<ClInclude Include="src\xenia\base\memory.h" />
|
<ClInclude Include="src\xenia\base\memory.h" />
|
||||||
|
<ClInclude Include="src\xenia\base\mutex.h" />
|
||||||
<ClInclude Include="src\xenia\base\platform.h" />
|
<ClInclude Include="src\xenia\base\platform.h" />
|
||||||
<ClInclude Include="src\xenia\base\reset_scope.h" />
|
<ClInclude Include="src\xenia\base\reset_scope.h" />
|
||||||
<ClInclude Include="src\xenia\base\string.h" />
|
<ClInclude Include="src\xenia\base\string.h" />
|
||||||
|
|
|
@ -404,6 +404,7 @@
|
||||||
<ClInclude Include="src\xenia\debug\proto\control_generated.h" />
|
<ClInclude Include="src\xenia\debug\proto\control_generated.h" />
|
||||||
<ClInclude Include="src\xenia\debug\proto\modules_generated.h" />
|
<ClInclude Include="src\xenia\debug\proto\modules_generated.h" />
|
||||||
<ClInclude Include="src\xenia\debug\proto\threads_generated.h" />
|
<ClInclude Include="src\xenia\debug\proto\threads_generated.h" />
|
||||||
|
<ClInclude Include="src\xenia\base\mutex.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="src\xenia\cpu\backend\x64\x64_sequence.inl" />
|
<None Include="src\xenia\cpu\backend\x64\x64_sequence.inl" />
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XENIA_BASE_MUTEX_H_
|
||||||
|
#define XENIA_BASE_MUTEX_H_
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "xenia/base/platform.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
|
||||||
|
// This type should be interchangable with std::mutex, only it provides the
|
||||||
|
// ability to resume threads that hold the lock when the debugger needs it.
|
||||||
|
class mutex {
|
||||||
|
public:
|
||||||
|
mutex(int _Flags = 0) noexcept {
|
||||||
|
_Mtx_init_in_situ(_Mymtx(), _Flags | _Mtx_try);
|
||||||
|
}
|
||||||
|
|
||||||
|
~mutex() noexcept { _Mtx_destroy_in_situ(_Mymtx()); }
|
||||||
|
|
||||||
|
mutex(const mutex&) = delete;
|
||||||
|
mutex& operator=(const mutex&) = delete;
|
||||||
|
|
||||||
|
void lock() {
|
||||||
|
_Mtx_lock(_Mymtx());
|
||||||
|
holding_thread_ = ::GetCurrentThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_lock() {
|
||||||
|
if (_Mtx_trylock(_Mymtx()) == _Thrd_success) {
|
||||||
|
holding_thread_ = ::GetCurrentThread();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lock_as_debugger() {
|
||||||
|
if (_Mtx_trylock(_Mymtx()) == _Thrd_success) {
|
||||||
|
// Nothing holding it.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Resume the thread holding it, which will unlock and suspend itself.
|
||||||
|
debugger_waiting_ = true;
|
||||||
|
ResumeThread(holding_thread_);
|
||||||
|
lock();
|
||||||
|
debugger_waiting_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock() {
|
||||||
|
bool debugger_waiting = debugger_waiting_;
|
||||||
|
_Mtx_unlock(_Mymtx());
|
||||||
|
if (debugger_waiting) {
|
||||||
|
SuspendThread(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void* native_handle_type;
|
||||||
|
|
||||||
|
native_handle_type native_handle() { return (_Mtx_getconcrtcs(_Mymtx())); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::aligned_storage<_Mtx_internal_imp_size,
|
||||||
|
_Mtx_internal_imp_alignment>::type _Mtx_storage;
|
||||||
|
HANDLE holding_thread_;
|
||||||
|
bool debugger_waiting_;
|
||||||
|
|
||||||
|
_Mtx_t _Mymtx() noexcept { return (reinterpret_cast<_Mtx_t>(&_Mtx_storage)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class recursive_mutex : public mutex {
|
||||||
|
public:
|
||||||
|
recursive_mutex() : mutex(_Mtx_recursive) {}
|
||||||
|
|
||||||
|
bool try_lock() noexcept { return mutex::try_lock(); }
|
||||||
|
|
||||||
|
recursive_mutex(const recursive_mutex&) = delete;
|
||||||
|
recursive_mutex& operator=(const recursive_mutex&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
#endif // XENIA_BASE_MUTEX_H_
|
|
@ -107,7 +107,7 @@ bool KernelState::IsKernelModule(const char* name) {
|
||||||
// Executing module isn't a kernel module.
|
// Executing module isn't a kernel module.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
|
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||||
for (auto kernel_module : kernel_modules_) {
|
for (auto kernel_module : kernel_modules_) {
|
||||||
if (kernel_module->Matches(name)) {
|
if (kernel_module->Matches(name)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -125,7 +125,7 @@ XModule* KernelState::GetModule(const char* name) {
|
||||||
// Some games request this, for some reason. wtf.
|
// Some games request this, for some reason. wtf.
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
|
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||||
for (auto kernel_module : kernel_modules_) {
|
for (auto kernel_module : kernel_modules_) {
|
||||||
if (kernel_module->Matches(name)) {
|
if (kernel_module->Matches(name)) {
|
||||||
kernel_module->Retain();
|
kernel_module->Retain();
|
||||||
|
@ -165,7 +165,7 @@ void KernelState::SetExecutableModule(XUserModule* module) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelState::LoadKernelModule(XKernelModule* kernel_module) {
|
void KernelState::LoadKernelModule(XKernelModule* kernel_module) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
|
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||||
kernel_modules_.push_back(kernel_module);
|
kernel_modules_.push_back(kernel_module);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ XUserModule* KernelState::LoadUserModule(const char* raw_name) {
|
||||||
|
|
||||||
XUserModule* module = nullptr;
|
XUserModule* module = nullptr;
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
|
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||||
|
|
||||||
// See if we've already loaded it
|
// See if we've already loaded it
|
||||||
for (XUserModule* existing_module : user_modules_) {
|
for (XUserModule* existing_module : user_modules_) {
|
||||||
|
@ -221,12 +221,12 @@ XUserModule* KernelState::LoadUserModule(const char* raw_name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelState::RegisterThread(XThread* thread) {
|
void KernelState::RegisterThread(XThread* thread) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
|
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||||
threads_by_id_[thread->thread_id()] = thread;
|
threads_by_id_[thread->thread_id()] = thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelState::UnregisterThread(XThread* thread) {
|
void KernelState::UnregisterThread(XThread* thread) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
|
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||||
auto it = threads_by_id_.find(thread->thread_id());
|
auto it = threads_by_id_.find(thread->thread_id());
|
||||||
if (it != threads_by_id_.end()) {
|
if (it != threads_by_id_.end()) {
|
||||||
threads_by_id_.erase(it);
|
threads_by_id_.erase(it);
|
||||||
|
@ -234,7 +234,7 @@ void KernelState::UnregisterThread(XThread* thread) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelState::OnThreadExecute(XThread* thread) {
|
void KernelState::OnThreadExecute(XThread* thread) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
|
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||||
|
|
||||||
// Must be called on executing thread.
|
// Must be called on executing thread.
|
||||||
assert_true(XThread::GetCurrentThread() == thread);
|
assert_true(XThread::GetCurrentThread() == thread);
|
||||||
|
@ -257,7 +257,7 @@ void KernelState::OnThreadExecute(XThread* thread) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelState::OnThreadExit(XThread* thread) {
|
void KernelState::OnThreadExit(XThread* thread) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
|
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||||
|
|
||||||
// Must be called on executing thread.
|
// Must be called on executing thread.
|
||||||
assert_true(XThread::GetCurrentThread() == thread);
|
assert_true(XThread::GetCurrentThread() == thread);
|
||||||
|
@ -280,7 +280,7 @@ void KernelState::OnThreadExit(XThread* thread) {
|
||||||
}
|
}
|
||||||
|
|
||||||
XThread* KernelState::GetThreadByID(uint32_t thread_id) {
|
XThread* KernelState::GetThreadByID(uint32_t thread_id) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
|
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||||
XThread* thread = nullptr;
|
XThread* thread = nullptr;
|
||||||
auto it = threads_by_id_.find(thread_id);
|
auto it = threads_by_id_.find(thread_id);
|
||||||
if (it != threads_by_id_.end()) {
|
if (it != threads_by_id_.end()) {
|
||||||
|
@ -292,7 +292,7 @@ XThread* KernelState::GetThreadByID(uint32_t thread_id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelState::RegisterNotifyListener(XNotifyListener* listener) {
|
void KernelState::RegisterNotifyListener(XNotifyListener* listener) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
|
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||||
notify_listeners_.push_back(listener);
|
notify_listeners_.push_back(listener);
|
||||||
|
|
||||||
// Games seem to expect a few notifications on startup, only for the first
|
// Games seem to expect a few notifications on startup, only for the first
|
||||||
|
@ -316,7 +316,7 @@ void KernelState::RegisterNotifyListener(XNotifyListener* listener) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelState::UnregisterNotifyListener(XNotifyListener* listener) {
|
void KernelState::UnregisterNotifyListener(XNotifyListener* listener) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
|
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||||
for (auto it = notify_listeners_.begin(); it != notify_listeners_.end();
|
for (auto it = notify_listeners_.begin(); it != notify_listeners_.end();
|
||||||
++it) {
|
++it) {
|
||||||
if (*it == listener) {
|
if (*it == listener) {
|
||||||
|
@ -327,7 +327,7 @@ void KernelState::UnregisterNotifyListener(XNotifyListener* listener) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelState::BroadcastNotification(XNotificationID id, uint32_t data) {
|
void KernelState::BroadcastNotification(XNotificationID id, uint32_t data) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
|
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||||
for (auto it = notify_listeners_.begin(); it != notify_listeners_.end();
|
for (auto it = notify_listeners_.begin(); it != notify_listeners_.end();
|
||||||
++it) {
|
++it) {
|
||||||
(*it)->EnqueueNotification(id, data);
|
(*it)->EnqueueNotification(id, data);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
#include "xenia/base/mutex.h"
|
||||||
#include "xenia/cpu/export_resolver.h"
|
#include "xenia/cpu/export_resolver.h"
|
||||||
#include "xenia/kernel/app.h"
|
#include "xenia/kernel/app.h"
|
||||||
#include "xenia/kernel/content_manager.h"
|
#include "xenia/kernel/content_manager.h"
|
||||||
|
@ -64,7 +65,7 @@ class KernelState {
|
||||||
ContentManager* content_manager() const { return content_manager_.get(); }
|
ContentManager* content_manager() const { return content_manager_.get(); }
|
||||||
|
|
||||||
ObjectTable* object_table() const { return object_table_; }
|
ObjectTable* object_table() const { return object_table_; }
|
||||||
std::recursive_mutex& object_mutex() { return object_mutex_; }
|
xe::recursive_mutex& object_mutex() { return object_mutex_; }
|
||||||
|
|
||||||
uint32_t process_type() const { return process_type_; }
|
uint32_t process_type() const { return process_type_; }
|
||||||
void set_process_type(uint32_t value) { process_type_ = value; }
|
void set_process_type(uint32_t value) { process_type_ = value; }
|
||||||
|
@ -115,7 +116,7 @@ class KernelState {
|
||||||
std::unique_ptr<ContentManager> content_manager_;
|
std::unique_ptr<ContentManager> content_manager_;
|
||||||
|
|
||||||
ObjectTable* object_table_;
|
ObjectTable* object_table_;
|
||||||
std::recursive_mutex object_mutex_;
|
xe::recursive_mutex object_mutex_;
|
||||||
std::unordered_map<uint32_t, XThread*> threads_by_id_;
|
std::unordered_map<uint32_t, XThread*> threads_by_id_;
|
||||||
std::vector<XNotifyListener*> notify_listeners_;
|
std::vector<XNotifyListener*> notify_listeners_;
|
||||||
bool has_notified_startup_;
|
bool has_notified_startup_;
|
||||||
|
|
|
@ -153,7 +153,7 @@ X_STATUS XObject::WaitMultiple(uint32_t count, XObject** objects,
|
||||||
}
|
}
|
||||||
|
|
||||||
void XObject::SetNativePointer(uint32_t native_ptr, bool uninitialized) {
|
void XObject::SetNativePointer(uint32_t native_ptr, bool uninitialized) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(kernel_state_->object_mutex());
|
std::lock_guard<xe::recursive_mutex> lock(kernel_state_->object_mutex());
|
||||||
|
|
||||||
auto header =
|
auto header =
|
||||||
kernel_state_->memory()->TranslateVirtual<DISPATCH_HEADER*>(native_ptr);
|
kernel_state_->memory()->TranslateVirtual<DISPATCH_HEADER*>(native_ptr);
|
||||||
|
@ -183,7 +183,7 @@ XObject* XObject::GetObject(KernelState* kernel_state, void* native_ptr,
|
||||||
// We identify this by checking the low bit of wait_list_blink - if it's 1,
|
// We identify this by checking the low bit of wait_list_blink - if it's 1,
|
||||||
// we have already put our pointer in there.
|
// we have already put our pointer in there.
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(kernel_state->object_mutex());
|
std::lock_guard<xe::recursive_mutex> lock(kernel_state->object_mutex());
|
||||||
|
|
||||||
auto header = reinterpret_cast<DISPATCH_HEADER*>(native_ptr);
|
auto header = reinterpret_cast<DISPATCH_HEADER*>(native_ptr);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue