[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.
This commit is contained in:
emoose 2019-08-04 03:55:57 +01:00
parent 0ac83f99dc
commit c3476e8e19
No known key found for this signature in database
GPG Key ID: 3735C67912F5FF97
2 changed files with 24 additions and 28 deletions

View File

@ -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<XNotificationID, uint32_t>(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<uint32_t>(pair.first);
stream->Write<uint32_t>(pair.second);
@ -107,12 +104,12 @@ object_ref<XNotifyListener> XNotifyListener::Restore(KernelState* kernel_state,
notify->RestoreObject(stream);
notify->Initialize(stream->Read<uint64_t>());
notify->notification_count_ = stream->Read<size_t>();
for (size_t i = 0; i < notify->notification_count_; i++) {
auto notification_count_ = stream->Read<size_t>();
for (size_t i = 0; i < notification_count_; i++) {
std::pair<XNotificationID, uint32_t> pair;
pair.first = stream->Read<uint32_t>();
pair.second = stream->Read<uint32_t>();
notify->notifications_.insert(pair);
notify->notifications_.push_back(pair);
}
return object_ref<XNotifyListener>(notify);

View File

@ -48,8 +48,7 @@ class XNotifyListener : public XObject {
private:
std::unique_ptr<xe::threading::Event> wait_handle_;
xe::global_critical_region global_critical_region_;
std::unordered_map<XNotificationID, uint32_t> notifications_;
size_t notification_count_ = 0;
std::vector<std::pair<XNotificationID, uint32_t>> notifications_;
uint64_t mask_ = 0;
};