aboutsummaryrefslogtreecommitdiff
path: root/src/tests/core/priority_queue.cpp
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-11-02 23:55:21 +0100
committercirakg <cirakg@cirakg.xyz>2026-11-02 23:55:21 +0100
commit172aeaa0449d5618cff5753073a5c1741d619689 (patch)
treeefaccbdee41a9f1c5afd38ff47e53d4862147836 /src/tests/core/priority_queue.cpp
parente97daaf0fbb6cc8ac10ff0d2ff11ebe5da143442 (diff)
parent8362c44ff835d7be73d2adad9ce3e2d4467a6aeb (diff)
Merge upstream Djihads80/Eglantine nx2 into nx2
Diffstat (limited to 'src/tests/core/priority_queue.cpp')
-rw-r--r--src/tests/core/priority_queue.cpp111
1 files changed, 111 insertions, 0 deletions
diff --git a/src/tests/core/priority_queue.cpp b/src/tests/core/priority_queue.cpp
new file mode 100644
index 0000000000..0d7174f793
--- /dev/null
+++ b/src/tests/core/priority_queue.cpp
@@ -0,0 +1,111 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include <algorithm>
+#include <array>
+#include <random>
+#include <vector>
+#include <catch2/catch_test_macros.hpp>
+#include "core/hle/kernel/k_priority_queue.h"
+
+namespace {
+struct Affinity {
+ u64 GetAffinityMask() const {
+ return 3;
+ }
+ void SetAffinityMask(u64) {}
+ bool GetAffinity(s32) const {
+ return true;
+ }
+ void SetAffinity(s32, bool) {}
+ void SetAll() {}
+};
+
+struct Member {
+ struct QueueEntry {
+ Member* prev{};
+ Member* next{};
+ void Initialize() {
+ prev = next = nullptr;
+ }
+ void SetPrev(Member* value) {
+ prev = value;
+ }
+ void SetNext(Member* value) {
+ next = value;
+ }
+ Member* GetNext() const {
+ return next;
+ }
+ Member* GetPrev() const {
+ return prev;
+ }
+ };
+ std::array<QueueEntry, 2> entries{};
+ s32 priority{};
+ QueueEntry& GetPriorityQueueEntry(s32 core) {
+ return entries[core];
+ }
+ const QueueEntry& GetPriorityQueueEntry(s32 core) const {
+ return entries[core];
+ }
+ Affinity GetAffinityMask() const {
+ return {};
+ }
+ s32 GetActiveCore() const {
+ return 0;
+ }
+ s32 GetPriority() const {
+ return priority;
+ }
+ bool IsDummyThread() const {
+ return false;
+ }
+};
+
+template <size_t Priorities>
+void CheckQueue() {
+ using Queue = Kernel::KPriorityQueue<Member, 2, Priorities - 1, 0>;
+ typename Queue::KPriorityQueueImpl queue;
+ std::array<Member, 160> members{};
+ std::array<std::array<bool, 2>, 160> present{};
+ std::array<std::array<std::vector<Member*>, Priorities>, 2> model{};
+ std::mt19937 random{6152};
+ for (size_t i = 0; i < members.size(); ++i) {
+ members[i].priority = static_cast<s32>(i % Priorities);
+ }
+ REQUIRE(queue.GetFront(0) == nullptr);
+ for (u32 operation = 0; operation < 3000; ++operation) {
+ const size_t index = random() % members.size();
+ const s32 core = random() % 2;
+ auto& member = members[index];
+ auto& expected = model[core][member.priority];
+ if (present[index][core]) {
+ queue.Remove(member.priority, core, &member);
+ std::erase(expected, &member);
+ } else if ((random() & 1) != 0) {
+ queue.PushFront(member.priority, core, &member);
+ expected.insert(expected.begin(), &member);
+ } else {
+ queue.PushBack(member.priority, core, &member);
+ expected.push_back(&member);
+ }
+ present[index][core] = !present[index][core];
+ for (s32 checked_core = 0; checked_core < 2; ++checked_core) {
+ Member* actual = queue.GetFront(checked_core);
+ for (const auto& priority : model[checked_core]) {
+ for (Member* wanted : priority) {
+ REQUIRE(actual == wanted);
+ actual = queue.GetNext(checked_core, actual);
+ }
+ }
+ REQUIRE(actual == nullptr);
+ }
+ }
+}
+} // namespace
+
+TEST_CASE("Priority queue bitmap traversal preserves thread order", "[core]") {
+ CheckQueue<64>();
+ CheckQueue<128>();
+}