DANGER DANGER. Switching to global critical region.
This changes almost all locks held by guest threads to use a single global critical region. This emulates the behavior on the PPC of disabling interrupts (by calls like KeRaiseIrqlToDpcLevel or masking interrupts), and prevents deadlocks from occuring when threads are suspended or otherwise blocked. This has performance implications and a pass is needed to ensure the locking is as granular as possible. It could also break everything because it's fundamentally unsound. We'll see.
This commit is contained in:
@@ -81,7 +81,7 @@ X_RESULT XXMPApp::XMPCreateTitlePlaylist(
|
||||
xe::store_and_swap<uint32_t>(memory_->TranslateVirtual(out_playlist_handle),
|
||||
playlist->handle);
|
||||
|
||||
std::lock_guard<xe::mutex> lock(mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
playlists_.insert({playlist->handle, playlist.get()});
|
||||
playlist.release();
|
||||
return X_ERROR_SUCCESS;
|
||||
@@ -89,7 +89,7 @@ X_RESULT XXMPApp::XMPCreateTitlePlaylist(
|
||||
|
||||
X_RESULT XXMPApp::XMPDeleteTitlePlaylist(uint32_t playlist_handle) {
|
||||
XELOGD("XMPDeleteTitlePlaylist(%.8X)", playlist_handle);
|
||||
std::lock_guard<xe::mutex> lock(mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
auto it = playlists_.find(playlist_handle);
|
||||
if (it == playlists_.end()) {
|
||||
XELOGE("Playlist %.8X not found", playlist_handle);
|
||||
@@ -109,7 +109,7 @@ X_RESULT XXMPApp::XMPPlayTitlePlaylist(uint32_t playlist_handle,
|
||||
XELOGD("XMPPlayTitlePlaylist(%.8X, %.8X)", playlist_handle, song_handle);
|
||||
Playlist* playlist = nullptr;
|
||||
{
|
||||
std::lock_guard<xe::mutex> lock(mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
auto it = playlists_.find(playlist_handle);
|
||||
if (it == playlists_.end()) {
|
||||
XELOGE("Playlist %.8X not found", playlist_handle);
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#define XENIA_KERNEL_APPS_XMP_APP_H_
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -102,7 +101,7 @@ class XXMPApp : public XApp {
|
||||
Playlist* active_playlist_;
|
||||
int active_song_index_;
|
||||
|
||||
xe::mutex mutex_;
|
||||
xe::global_critical_region global_critical_region_;
|
||||
std::unordered_map<uint32_t, Playlist*> playlists_;
|
||||
uint32_t next_playlist_handle_;
|
||||
uint32_t next_song_handle_;
|
||||
|
||||
@@ -125,7 +125,7 @@ std::unique_ptr<ContentPackage> ContentManager::ResolvePackage(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::lock_guard<xe::recursive_mutex> lock(content_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
auto package = std::make_unique<ContentPackage>(kernel_state_, root_name,
|
||||
data, package_path);
|
||||
@@ -139,7 +139,7 @@ bool ContentManager::ContentExists(const XCONTENT_DATA& data) {
|
||||
|
||||
X_RESULT ContentManager::CreateContent(std::string root_name,
|
||||
const XCONTENT_DATA& data) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(content_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
if (open_packages_.count(root_name)) {
|
||||
// Already content open with this root name.
|
||||
@@ -166,7 +166,7 @@ X_RESULT ContentManager::CreateContent(std::string root_name,
|
||||
|
||||
X_RESULT ContentManager::OpenContent(std::string root_name,
|
||||
const XCONTENT_DATA& data) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(content_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
if (open_packages_.count(root_name)) {
|
||||
// Already content open with this root name.
|
||||
@@ -189,7 +189,7 @@ X_RESULT ContentManager::OpenContent(std::string root_name,
|
||||
}
|
||||
|
||||
X_RESULT ContentManager::CloseContent(std::string root_name) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(content_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
auto it = open_packages_.find(root_name);
|
||||
if (it == open_packages_.end()) {
|
||||
@@ -205,7 +205,7 @@ X_RESULT ContentManager::CloseContent(std::string root_name) {
|
||||
|
||||
X_RESULT ContentManager::GetContentThumbnail(const XCONTENT_DATA& data,
|
||||
std::vector<uint8_t>* buffer) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(content_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
auto package_path = ResolvePackagePath(data);
|
||||
auto thumb_path = xe::join_paths(package_path, kThumbnailFileName);
|
||||
if (xe::filesystem::PathExists(thumb_path)) {
|
||||
@@ -224,7 +224,7 @@ X_RESULT ContentManager::GetContentThumbnail(const XCONTENT_DATA& data,
|
||||
|
||||
X_RESULT ContentManager::SetContentThumbnail(const XCONTENT_DATA& data,
|
||||
std::vector<uint8_t> buffer) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(content_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
auto package_path = ResolvePackagePath(data);
|
||||
xe::filesystem::CreateFolder(package_path);
|
||||
if (xe::filesystem::PathExists(package_path)) {
|
||||
@@ -239,7 +239,7 @@ X_RESULT ContentManager::SetContentThumbnail(const XCONTENT_DATA& data,
|
||||
}
|
||||
|
||||
X_RESULT ContentManager::DeleteContent(const XCONTENT_DATA& data) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(content_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
auto package_path = ResolvePackagePath(data);
|
||||
if (xe::filesystem::PathExists(package_path)) {
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#define XENIA_KERNEL_CONTENT_MANAGER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -88,7 +87,7 @@ class ContentManager {
|
||||
KernelState* kernel_state_;
|
||||
std::wstring root_path_;
|
||||
|
||||
xe::recursive_mutex content_mutex_;
|
||||
xe::global_critical_region global_critical_region_;
|
||||
std::unordered_map<std::string, ContentPackage*> open_packages_;
|
||||
};
|
||||
|
||||
|
||||
@@ -22,9 +22,5 @@ Dispatcher::Dispatcher(KernelState* kernel_state)
|
||||
|
||||
Dispatcher::~Dispatcher() { delete dpc_list_; }
|
||||
|
||||
void Dispatcher::Lock() { lock_.lock(); }
|
||||
|
||||
void Dispatcher::Unlock() { lock_.unlock(); }
|
||||
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
#ifndef XENIA_KERNEL_DISPATCHER_H_
|
||||
#define XENIA_KERNEL_DISPATCHER_H_
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "xenia/base/mutex.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
namespace xe {
|
||||
@@ -21,6 +18,7 @@ namespace kernel {
|
||||
class KernelState;
|
||||
class NativeList;
|
||||
|
||||
// All access must be guarded by the global critical section.
|
||||
class Dispatcher {
|
||||
public:
|
||||
explicit Dispatcher(KernelState* kernel_state);
|
||||
@@ -28,16 +26,10 @@ class Dispatcher {
|
||||
|
||||
KernelState* kernel_state() const { return kernel_state_; }
|
||||
|
||||
void Lock();
|
||||
void Unlock();
|
||||
|
||||
NativeList* dpc_list() const { return dpc_list_; }
|
||||
|
||||
private:
|
||||
private:
|
||||
KernelState* kernel_state_;
|
||||
|
||||
xe::mutex lock_;
|
||||
NativeList* dpc_list_;
|
||||
};
|
||||
|
||||
|
||||
@@ -174,7 +174,7 @@ bool KernelState::IsKernelModule(const char* name) {
|
||||
// Executing module isn't a kernel module.
|
||||
return false;
|
||||
}
|
||||
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
for (auto kernel_module : kernel_modules_) {
|
||||
if (kernel_module->Matches(name)) {
|
||||
return true;
|
||||
@@ -204,7 +204,7 @@ object_ref<XModule> KernelState::GetModule(const char* name) {
|
||||
// Some games request this, for some reason. wtf.
|
||||
return nullptr;
|
||||
}
|
||||
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
for (auto kernel_module : kernel_modules_) {
|
||||
if (kernel_module->Matches(name)) {
|
||||
return retain_object(kernel_module.get());
|
||||
@@ -262,9 +262,9 @@ void KernelState::SetExecutableModule(object_ref<XUserModule> module) {
|
||||
dispatch_thread_ =
|
||||
object_ref<XHostThread>(new XHostThread(this, 128 * 1024, 0, [this]() {
|
||||
while (dispatch_thread_running_) {
|
||||
std::unique_lock<std::mutex> lock(dispatch_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
if (dispatch_queue_.empty()) {
|
||||
dispatch_cond_.wait(lock);
|
||||
dispatch_cond_.wait(global_lock);
|
||||
if (!dispatch_thread_running_) {
|
||||
break;
|
||||
}
|
||||
@@ -281,7 +281,7 @@ void KernelState::SetExecutableModule(object_ref<XUserModule> module) {
|
||||
}
|
||||
|
||||
void KernelState::LoadKernelModule(object_ref<XKernelModule> kernel_module) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
kernel_modules_.push_back(std::move(kernel_module));
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ object_ref<XUserModule> KernelState::LoadUserModule(const char* raw_name) {
|
||||
|
||||
object_ref<XUserModule> module;
|
||||
{
|
||||
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
// See if we've already loaded it
|
||||
for (auto& existing_module : user_modules_) {
|
||||
@@ -337,7 +337,7 @@ object_ref<XUserModule> KernelState::LoadUserModule(const char* raw_name) {
|
||||
}
|
||||
|
||||
void KernelState::TerminateTitle(bool from_guest_thread) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
// First: call terminate routines.
|
||||
// TODO(benvanik): these might take arguments.
|
||||
@@ -391,13 +391,13 @@ void KernelState::TerminateTitle(bool from_guest_thread) {
|
||||
// code anymore)
|
||||
// Also, manually invoke the lock guard's destructor, because Terminate
|
||||
// does not return.
|
||||
lock.~lock_guard();
|
||||
global_lock.unlock();
|
||||
XThread::GetCurrentThread()->Terminate(0);
|
||||
}
|
||||
}
|
||||
|
||||
void KernelState::RegisterThread(XThread* thread) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
threads_by_id_[thread->thread_id()] = thread;
|
||||
|
||||
auto pib =
|
||||
@@ -406,7 +406,7 @@ void KernelState::RegisterThread(XThread* thread) {
|
||||
}
|
||||
|
||||
void KernelState::UnregisterThread(XThread* thread) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
auto it = threads_by_id_.find(thread->thread_id());
|
||||
if (it != threads_by_id_.end()) {
|
||||
threads_by_id_.erase(it);
|
||||
@@ -418,7 +418,7 @@ void KernelState::UnregisterThread(XThread* thread) {
|
||||
}
|
||||
|
||||
void KernelState::OnThreadExecute(XThread* thread) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
// Must be called on executing thread.
|
||||
assert_true(XThread::GetCurrentThread() == thread);
|
||||
@@ -440,7 +440,7 @@ void KernelState::OnThreadExecute(XThread* thread) {
|
||||
}
|
||||
|
||||
void KernelState::OnThreadExit(XThread* thread) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
// Must be called on executing thread.
|
||||
assert_true(XThread::GetCurrentThread() == thread);
|
||||
@@ -466,7 +466,7 @@ void KernelState::OnThreadExit(XThread* thread) {
|
||||
}
|
||||
|
||||
object_ref<XThread> KernelState::GetThreadByID(uint32_t thread_id) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
XThread* thread = nullptr;
|
||||
auto it = threads_by_id_.find(thread_id);
|
||||
if (it != threads_by_id_.end()) {
|
||||
@@ -476,7 +476,7 @@ object_ref<XThread> KernelState::GetThreadByID(uint32_t thread_id) {
|
||||
}
|
||||
|
||||
void KernelState::RegisterNotifyListener(XNotifyListener* listener) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
notify_listeners_.push_back(retain_object(listener));
|
||||
|
||||
// Games seem to expect a few notifications on startup, only for the first
|
||||
@@ -500,7 +500,7 @@ void KernelState::RegisterNotifyListener(XNotifyListener* listener) {
|
||||
}
|
||||
|
||||
void KernelState::UnregisterNotifyListener(XNotifyListener* listener) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
for (auto it = notify_listeners_.begin(); it != notify_listeners_.end();
|
||||
++it) {
|
||||
if ((*it).get() == listener) {
|
||||
@@ -511,7 +511,7 @@ void KernelState::UnregisterNotifyListener(XNotifyListener* listener) {
|
||||
}
|
||||
|
||||
void KernelState::BroadcastNotification(XNotificationID id, uint32_t data) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
for (auto it = notify_listeners_.begin(); it != notify_listeners_.end();
|
||||
++it) {
|
||||
(*it)->EnqueueNotification(id, data);
|
||||
@@ -574,7 +574,7 @@ void KernelState::CompleteOverlappedDeferredEx(
|
||||
auto ptr = memory()->TranslateVirtual(overlapped_ptr);
|
||||
XOverlappedSetResult(ptr, X_ERROR_IO_PENDING);
|
||||
XOverlappedSetContext(ptr, XThread::GetCurrentThreadHandle());
|
||||
std::unique_lock<std::mutex> lock(dispatch_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
dispatch_queue_.push_back([this, completion_callback, overlapped_ptr, result,
|
||||
extended_error, length]() {
|
||||
xe::threading::Sleep(
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/mutex.h"
|
||||
@@ -105,8 +104,8 @@ class KernelState {
|
||||
UserProfile* user_profile() const { return user_profile_.get(); }
|
||||
ContentManager* content_manager() const { return content_manager_.get(); }
|
||||
|
||||
// Access must be guarded by the global critical region.
|
||||
ObjectTable* object_table() const { return object_table_; }
|
||||
xe::recursive_mutex& object_mutex() { return object_mutex_; }
|
||||
|
||||
uint32_t process_type() const;
|
||||
void set_process_type(uint32_t value);
|
||||
@@ -178,8 +177,10 @@ class KernelState {
|
||||
std::unique_ptr<UserProfile> user_profile_;
|
||||
std::unique_ptr<ContentManager> content_manager_;
|
||||
|
||||
xe::global_critical_region global_critical_region_;
|
||||
|
||||
// Must be guarded by the global critical region.
|
||||
ObjectTable* object_table_;
|
||||
xe::recursive_mutex object_mutex_;
|
||||
std::unordered_map<uint32_t, XThread*> threads_by_id_;
|
||||
std::vector<object_ref<XNotifyListener>> notify_listeners_;
|
||||
bool has_notified_startup_;
|
||||
@@ -194,8 +195,8 @@ class KernelState {
|
||||
|
||||
std::atomic<bool> dispatch_thread_running_;
|
||||
object_ref<XHostThread> dispatch_thread_;
|
||||
std::mutex dispatch_mutex_;
|
||||
std::condition_variable dispatch_cond_;
|
||||
// Must be guarded by the global critical region.
|
||||
std::condition_variable_any dispatch_cond_;
|
||||
std::list<std::function<void()>> dispatch_queue_;
|
||||
|
||||
friend class XObject;
|
||||
|
||||
@@ -22,7 +22,7 @@ ObjectTable::ObjectTable()
|
||||
: table_capacity_(0), table_(nullptr), last_free_entry_(0) {}
|
||||
|
||||
ObjectTable::~ObjectTable() {
|
||||
std::lock_guard<xe::recursive_mutex> lock(table_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
// Release all objects.
|
||||
for (uint32_t n = 0; n < table_capacity_; n++) {
|
||||
@@ -89,7 +89,7 @@ X_STATUS ObjectTable::AddHandle(XObject* object, X_HANDLE* out_handle) {
|
||||
|
||||
uint32_t slot = 0;
|
||||
{
|
||||
std::lock_guard<xe::recursive_mutex> lock(table_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
// Find a free slot.
|
||||
result = FindFreeSlot(&slot);
|
||||
@@ -128,7 +128,7 @@ X_STATUS ObjectTable::DuplicateHandle(X_HANDLE handle, X_HANDLE* out_handle) {
|
||||
}
|
||||
|
||||
X_STATUS ObjectTable::RetainHandle(X_HANDLE handle) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(table_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
ObjectTableEntry* entry = LookupTable(handle);
|
||||
if (!entry) {
|
||||
@@ -140,7 +140,7 @@ X_STATUS ObjectTable::RetainHandle(X_HANDLE handle) {
|
||||
}
|
||||
|
||||
X_STATUS ObjectTable::ReleaseHandle(X_HANDLE handle) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(table_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
ObjectTableEntry* entry = LookupTable(handle);
|
||||
if (!entry) {
|
||||
@@ -170,7 +170,7 @@ X_STATUS ObjectTable::RemoveHandle(X_HANDLE handle) {
|
||||
return X_STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
std::lock_guard<xe::recursive_mutex> lock(table_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
if (entry->object) {
|
||||
auto object = entry->object;
|
||||
entry->object = nullptr;
|
||||
@@ -189,7 +189,7 @@ ObjectTable::ObjectTableEntry* ObjectTable::LookupTable(X_HANDLE handle) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::lock_guard<xe::recursive_mutex> lock(table_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
// Lower 2 bits are ignored.
|
||||
uint32_t slot = handle >> 2;
|
||||
@@ -208,7 +208,7 @@ XObject* ObjectTable::LookupObject(X_HANDLE handle, bool already_locked) {
|
||||
|
||||
XObject* object = nullptr;
|
||||
if (!already_locked) {
|
||||
table_mutex_.lock();
|
||||
global_critical_region_.mutex().lock();
|
||||
}
|
||||
|
||||
// Lower 2 bits are ignored.
|
||||
@@ -228,7 +228,7 @@ XObject* ObjectTable::LookupObject(X_HANDLE handle, bool already_locked) {
|
||||
}
|
||||
|
||||
if (!already_locked) {
|
||||
table_mutex_.unlock();
|
||||
global_critical_region_.mutex().unlock();
|
||||
}
|
||||
|
||||
return object;
|
||||
@@ -236,7 +236,7 @@ XObject* ObjectTable::LookupObject(X_HANDLE handle, bool already_locked) {
|
||||
|
||||
void ObjectTable::GetObjectsByType(XObject::Type type,
|
||||
std::vector<object_ref<XObject>>* results) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(table_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
for (uint32_t slot = 0; slot < table_capacity_; ++slot) {
|
||||
auto& entry = table_[slot];
|
||||
if (entry.object) {
|
||||
@@ -267,7 +267,7 @@ X_STATUS ObjectTable::AddNameMapping(const std::string& name, X_HANDLE handle) {
|
||||
std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(),
|
||||
tolower);
|
||||
|
||||
std::lock_guard<xe::recursive_mutex> lock(table_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
if (name_table_.count(lower_name)) {
|
||||
return X_STATUS_OBJECT_NAME_COLLISION;
|
||||
}
|
||||
@@ -281,7 +281,7 @@ void ObjectTable::RemoveNameMapping(const std::string& name) {
|
||||
std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(),
|
||||
tolower);
|
||||
|
||||
std::lock_guard<xe::recursive_mutex> lock(table_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
auto it = name_table_.find(lower_name);
|
||||
if (it != name_table_.end()) {
|
||||
name_table_.erase(it);
|
||||
@@ -295,7 +295,7 @@ X_STATUS ObjectTable::GetObjectByName(const std::string& name,
|
||||
std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(),
|
||||
tolower);
|
||||
|
||||
std::lock_guard<xe::recursive_mutex> lock(table_mutex_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
auto it = name_table_.find(lower_name);
|
||||
if (it == name_table_.end()) {
|
||||
*out_handle = X_INVALID_HANDLE_VALUE;
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#ifndef XENIA_KERNEL_OBJECT_TABLE_H_
|
||||
#define XENIA_KERNEL_OBJECT_TABLE_H_
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -65,7 +64,7 @@ class ObjectTable {
|
||||
X_HANDLE TranslateHandle(X_HANDLE handle);
|
||||
X_STATUS FindFreeSlot(uint32_t* out_slot);
|
||||
|
||||
xe::recursive_mutex table_mutex_;
|
||||
xe::global_critical_region global_critical_region_;
|
||||
uint32_t table_capacity_;
|
||||
ObjectTableEntry* table_;
|
||||
uint32_t last_free_entry_;
|
||||
|
||||
@@ -36,7 +36,7 @@ void XNotifyListener::EnqueueNotification(XNotificationID id, uint32_t data) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<xe::mutex> lock(lock_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
if (notifications_.count(id)) {
|
||||
// Already exists. Overwrite.
|
||||
notifications_[id] = data;
|
||||
@@ -50,7 +50,7 @@ void XNotifyListener::EnqueueNotification(XNotificationID id, uint32_t data) {
|
||||
|
||||
bool XNotifyListener::DequeueNotification(XNotificationID* out_id,
|
||||
uint32_t* out_data) {
|
||||
std::lock_guard<xe::mutex> lock(lock_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
bool dequeued = false;
|
||||
if (notification_count_) {
|
||||
dequeued = true;
|
||||
@@ -68,7 +68,7 @@ bool XNotifyListener::DequeueNotification(XNotificationID* out_id,
|
||||
|
||||
bool XNotifyListener::DequeueNotification(XNotificationID id,
|
||||
uint32_t* out_data) {
|
||||
std::lock_guard<xe::mutex> lock(lock_);
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
bool dequeued = false;
|
||||
if (notification_count_) {
|
||||
auto it = notifications_.find(id);
|
||||
|
||||
@@ -40,7 +40,7 @@ class XNotifyListener : public XObject {
|
||||
|
||||
private:
|
||||
std::unique_ptr<xe::threading::Event> wait_handle_;
|
||||
xe::mutex lock_;
|
||||
xe::global_critical_region global_critical_region_;
|
||||
std::unordered_map<XNotificationID, uint32_t> notifications_;
|
||||
size_t notification_count_ = 0;
|
||||
uint64_t mask_ = 0;
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "xenia/base/clock.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/base/mutex.h"
|
||||
#include "xenia/base/threading.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/emulator.h"
|
||||
@@ -36,7 +35,6 @@ namespace kernel {
|
||||
|
||||
uint32_t next_xthread_id_ = 0;
|
||||
thread_local XThread* current_thread_tls_ = nullptr;
|
||||
xe::mutex critical_region_;
|
||||
|
||||
XThread::XThread(KernelState* kernel_state, uint32_t stack_size,
|
||||
uint32_t xapi_thread_startup, uint32_t start_address,
|
||||
@@ -444,11 +442,12 @@ void XThread::Execute() {
|
||||
}
|
||||
|
||||
void XThread::EnterCriticalRegion() {
|
||||
// Global critical region. This isn't right, but is easy.
|
||||
critical_region_.lock();
|
||||
xe::global_critical_region::mutex().lock();
|
||||
}
|
||||
|
||||
void XThread::LeaveCriticalRegion() { critical_region_.unlock(); }
|
||||
void XThread::LeaveCriticalRegion() {
|
||||
xe::global_critical_region::mutex().unlock();
|
||||
}
|
||||
|
||||
uint32_t XThread::RaiseIrql(uint32_t new_irql) {
|
||||
return irql_.exchange(new_irql);
|
||||
@@ -458,11 +457,11 @@ void XThread::LowerIrql(uint32_t new_irql) { irql_ = new_irql; }
|
||||
|
||||
void XThread::CheckApcs() { DeliverAPCs(); }
|
||||
|
||||
void XThread::LockApc() { apc_lock_.lock(); }
|
||||
void XThread::LockApc() { EnterCriticalRegion(); }
|
||||
|
||||
void XThread::UnlockApc(bool queue_delivery) {
|
||||
bool needs_apc = apc_list_->HasPending();
|
||||
apc_lock_.unlock();
|
||||
LeaveCriticalRegion();
|
||||
if (needs_apc && queue_delivery) {
|
||||
thread_->QueueUserCallback([this]() { DeliverAPCs(); });
|
||||
}
|
||||
@@ -652,8 +651,15 @@ X_STATUS XThread::Resume(uint32_t* out_suspend_count) {
|
||||
}
|
||||
|
||||
X_STATUS XThread::Suspend(uint32_t* out_suspend_count) {
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
++guest_object<X_KTHREAD>()->suspend_count;
|
||||
|
||||
// If we are suspending ourselves, we can't hold the lock.
|
||||
if (XThread::GetCurrentThread() == this) {
|
||||
global_lock.unlock();
|
||||
}
|
||||
|
||||
if (thread_->Suspend(out_suspend_count)) {
|
||||
return X_STATUS_SUCCESS;
|
||||
} else {
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
#define XENIA_KERNEL_OBJECTS_XTHREAD_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include "xenia/base/mutex.h"
|
||||
#include "xenia/base/threading.h"
|
||||
#include "xenia/cpu/thread_state.h"
|
||||
#include "xenia/kernel/xobject.h"
|
||||
@@ -189,8 +189,8 @@ class XThread : public XObject {
|
||||
int32_t priority_ = 0;
|
||||
uint32_t affinity_ = 0;
|
||||
|
||||
xe::global_critical_region global_critical_region_;
|
||||
std::atomic<uint32_t> irql_ = {0};
|
||||
xe::mutex apc_lock_;
|
||||
NativeList* apc_list_ = nullptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -1274,15 +1274,13 @@ SHIM_CALL KeInsertQueueDpc_shim(PPCContext* ppc_context,
|
||||
uint32_t list_entry_ptr = dpc_ptr + 4;
|
||||
|
||||
// Lock dispatcher.
|
||||
auto global_lock = xe::global_critical_region::AcquireDirect();
|
||||
auto dispatcher = kernel_state->dispatcher();
|
||||
dispatcher->Lock();
|
||||
|
||||
auto dpc_list = dispatcher->dpc_list();
|
||||
|
||||
// If already in a queue, abort.
|
||||
if (dpc_list->IsQueued(list_entry_ptr)) {
|
||||
SHIM_SET_RETURN_32(0);
|
||||
dispatcher->Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1292,8 +1290,6 @@ SHIM_CALL KeInsertQueueDpc_shim(PPCContext* ppc_context,
|
||||
|
||||
dpc_list->Insert(list_entry_ptr);
|
||||
|
||||
dispatcher->Unlock();
|
||||
|
||||
SHIM_SET_RETURN_32(1);
|
||||
}
|
||||
|
||||
@@ -1307,8 +1303,8 @@ SHIM_CALL KeRemoveQueueDpc_shim(PPCContext* ppc_context,
|
||||
|
||||
uint32_t list_entry_ptr = dpc_ptr + 4;
|
||||
|
||||
auto global_lock = xe::global_critical_region::AcquireDirect();
|
||||
auto dispatcher = kernel_state->dispatcher();
|
||||
dispatcher->Lock();
|
||||
|
||||
auto dpc_list = dispatcher->dpc_list();
|
||||
if (dpc_list->IsQueued(list_entry_ptr)) {
|
||||
@@ -1316,8 +1312,6 @@ SHIM_CALL KeRemoveQueueDpc_shim(PPCContext* ppc_context,
|
||||
result = true;
|
||||
}
|
||||
|
||||
dispatcher->Unlock();
|
||||
|
||||
SHIM_SET_RETURN_32(result ? 1 : 0);
|
||||
}
|
||||
|
||||
@@ -1329,8 +1323,7 @@ pointer_result_t InterlockedPushEntrySList(
|
||||
|
||||
// Hold a global lock during this method. Once in the lock we assume we have
|
||||
// exclusive access to the structure.
|
||||
std::lock_guard<xe::recursive_mutex> lock(
|
||||
*kernel_state()->processor()->global_mutex());
|
||||
auto global_lock = xe::global_critical_region::AcquireDirect();
|
||||
|
||||
alignas(8) X_SLIST_HEADER old_hdr = *plist_ptr;
|
||||
alignas(8) X_SLIST_HEADER new_hdr = {0};
|
||||
@@ -1341,9 +1334,9 @@ pointer_result_t InterlockedPushEntrySList(
|
||||
entry->next = old_hdr.next.next;
|
||||
new_hdr.next.next = entry.guest_address();
|
||||
|
||||
xe::atomic_cas(*reinterpret_cast<uint64_t*>(&old_hdr),
|
||||
*reinterpret_cast<uint64_t*>(&new_hdr),
|
||||
reinterpret_cast<uint64_t*>(plist_ptr.host_address()));
|
||||
*reinterpret_cast<uint64_t*>(plist_ptr.host_address()) =
|
||||
*reinterpret_cast<uint64_t*>(&new_hdr);
|
||||
xe::threading::SyncMemory();
|
||||
|
||||
return old_head;
|
||||
}
|
||||
@@ -1355,8 +1348,7 @@ pointer_result_t InterlockedPopEntrySList(pointer_t<X_SLIST_HEADER> plist_ptr) {
|
||||
|
||||
// Hold a global lock during this method. Once in the lock we assume we have
|
||||
// exclusive access to the structure.
|
||||
std::lock_guard<xe::recursive_mutex> lock(
|
||||
*kernel_state()->processor()->global_mutex());
|
||||
auto global_lock = xe::global_critical_region::AcquireDirect();
|
||||
|
||||
uint32_t popped = 0;
|
||||
|
||||
@@ -1373,9 +1365,9 @@ pointer_result_t InterlockedPopEntrySList(pointer_t<X_SLIST_HEADER> plist_ptr) {
|
||||
new_hdr.next.next = next->next;
|
||||
new_hdr.sequence = old_hdr.sequence;
|
||||
|
||||
xe::atomic_cas(*reinterpret_cast<uint64_t*>(&old_hdr),
|
||||
*reinterpret_cast<uint64_t*>(&new_hdr),
|
||||
reinterpret_cast<uint64_t*>(plist_ptr.host_address()));
|
||||
*reinterpret_cast<uint64_t*>(plist_ptr.host_address()) =
|
||||
*reinterpret_cast<uint64_t*>(&new_hdr);
|
||||
xe::threading::SyncMemory();
|
||||
|
||||
return popped;
|
||||
}
|
||||
@@ -1387,8 +1379,7 @@ pointer_result_t InterlockedFlushSList(pointer_t<X_SLIST_HEADER> plist_ptr) {
|
||||
|
||||
// Hold a global lock during this method. Once in the lock we assume we have
|
||||
// exclusive access to the structure.
|
||||
std::lock_guard<xe::recursive_mutex> lock(
|
||||
*kernel_state()->processor()->global_mutex());
|
||||
auto global_lock = xe::global_critical_region::AcquireDirect();
|
||||
|
||||
alignas(8) X_SLIST_HEADER old_hdr = *plist_ptr;
|
||||
alignas(8) X_SLIST_HEADER new_hdr = {0};
|
||||
@@ -1397,9 +1388,9 @@ pointer_result_t InterlockedFlushSList(pointer_t<X_SLIST_HEADER> plist_ptr) {
|
||||
new_hdr.depth = 0;
|
||||
new_hdr.sequence = 0;
|
||||
|
||||
xe::atomic_cas(*reinterpret_cast<uint64_t*>(&old_hdr),
|
||||
*reinterpret_cast<uint64_t*>(&new_hdr),
|
||||
reinterpret_cast<uint64_t*>(plist_ptr.host_address()));
|
||||
*reinterpret_cast<uint64_t*>(plist_ptr.host_address()) =
|
||||
*reinterpret_cast<uint64_t*>(&new_hdr);
|
||||
xe::threading::SyncMemory();
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ X_STATUS XObject::WaitMultiple(uint32_t count, XObject** objects,
|
||||
}
|
||||
|
||||
uint8_t* XObject::CreateNative(uint32_t size) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(kernel_state_->object_mutex());
|
||||
auto global_lock = xe::global_critical_region::AcquireDirect();
|
||||
|
||||
uint32_t total_size = size + sizeof(X_OBJECT_HEADER);
|
||||
|
||||
@@ -255,7 +255,7 @@ uint8_t* XObject::CreateNative(uint32_t size) {
|
||||
}
|
||||
|
||||
void XObject::SetNativePointer(uint32_t native_ptr, bool uninitialized) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(kernel_state_->object_mutex());
|
||||
auto global_lock = xe::global_critical_region::AcquireDirect();
|
||||
|
||||
// If hit: We've already setup the native ptr with CreateNative!
|
||||
assert_zero(guest_object_ptr_);
|
||||
@@ -289,7 +289,7 @@ object_ref<XObject> XObject::GetNativeObject(KernelState* kernel_state,
|
||||
// We identify this by checking the low bit of wait_list_blink - if it's 1,
|
||||
// we have already put our pointer in there.
|
||||
|
||||
std::lock_guard<xe::recursive_mutex> lock(kernel_state->object_mutex());
|
||||
auto global_lock = xe::global_critical_region::AcquireDirect();
|
||||
|
||||
auto header = reinterpret_cast<X_DISPATCH_HEADER*>(native_ptr);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user