From c3476e8e194e184098a8bcb9be6cf5cc8772f780 Mon Sep 17 00:00:00 2001 From: emoose Date: Sun, 4 Aug 2019 03:55:57 +0100 Subject: [PATCH] [Kernel] Make XNotifyListener::notifications_ a std::vector, allowing multiple to use the same ID. Previously adding a notification that already exists would just overwrite the older notifications value, meaning the game would never see that older notification. This would break games like Project Sylpheed, which seems to require seeing XN_SYS_UI = true eventually followed by XN_SYS_UI = false for the game to realize all system UIs are closed. --- src/xenia/kernel/xnotifylistener.cc | 49 ++++++++++++++--------------- src/xenia/kernel/xnotifylistener.h | 3 +- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/xenia/kernel/xnotifylistener.cc b/src/xenia/kernel/xnotifylistener.cc index 747f53574..0770bd2d8 100644 --- a/src/xenia/kernel/xnotifylistener.cc +++ b/src/xenia/kernel/xnotifylistener.cc @@ -36,14 +36,7 @@ void XNotifyListener::EnqueueNotification(XNotificationID id, uint32_t data) { } auto global_lock = global_critical_region_.Acquire(); - if (notifications_.count(id)) { - // Already exists. Overwrite. - notifications_[id] = data; - } else { - // New. - notification_count_++; - notifications_.insert({id, data}); - } + notifications_.push_back(std::pair(id, data)); wait_handle_->Set(); } @@ -51,14 +44,13 @@ bool XNotifyListener::DequeueNotification(XNotificationID* out_id, uint32_t* out_data) { auto global_lock = global_critical_region_.Acquire(); bool dequeued = false; - if (notification_count_) { + if (notifications_.size()) { dequeued = true; auto it = notifications_.begin(); *out_id = it->first; *out_data = it->second; notifications_.erase(it); - notification_count_--; - if (!notification_count_) { + if (!notifications_.size()) { wait_handle_->Reset(); } } @@ -69,17 +61,22 @@ bool XNotifyListener::DequeueNotification(XNotificationID id, uint32_t* out_data) { auto global_lock = global_critical_region_.Acquire(); bool dequeued = false; - if (notification_count_) { - auto it = notifications_.find(id); - if (it != notifications_.end()) { - dequeued = true; - *out_data = it->second; - notifications_.erase(it); - notification_count_--; - if (!notification_count_) { - wait_handle_->Reset(); - } + if (!notifications_.size()) { + return dequeued; + } + + for (auto it = notifications_.begin(); it != notifications_.end(); ++it) { + if (it->first != id) { + continue; } + + dequeued = true; + *out_data = it->second; + notifications_.erase(it); + if (!notifications_.size()) { + wait_handle_->Reset(); + } + break; } return dequeued; } @@ -88,8 +85,8 @@ bool XNotifyListener::Save(ByteStream* stream) { SaveObject(stream); stream->Write(mask_); - stream->Write(notification_count_); - if (notification_count_) { + stream->Write(notifications_.size()); + if (notifications_.size()) { for (auto pair : notifications_) { stream->Write(pair.first); stream->Write(pair.second); @@ -107,12 +104,12 @@ object_ref XNotifyListener::Restore(KernelState* kernel_state, notify->RestoreObject(stream); notify->Initialize(stream->Read()); - notify->notification_count_ = stream->Read(); - for (size_t i = 0; i < notify->notification_count_; i++) { + auto notification_count_ = stream->Read(); + for (size_t i = 0; i < notification_count_; i++) { std::pair pair; pair.first = stream->Read(); pair.second = stream->Read(); - notify->notifications_.insert(pair); + notify->notifications_.push_back(pair); } return object_ref(notify); diff --git a/src/xenia/kernel/xnotifylistener.h b/src/xenia/kernel/xnotifylistener.h index 83599dd0b..800fa047d 100644 --- a/src/xenia/kernel/xnotifylistener.h +++ b/src/xenia/kernel/xnotifylistener.h @@ -48,8 +48,7 @@ class XNotifyListener : public XObject { private: std::unique_ptr wait_handle_; xe::global_critical_region global_critical_region_; - std::unordered_map notifications_; - size_t notification_count_ = 0; + std::vector> notifications_; uint64_t mask_ = 0; };