// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team // SPDX-License-Identifier: GPL-3.0+ #pragma once #include #include "common/Assertions.h" #include "common/Console.h" //Designed to allow one thread to queue data to another thread template class SimpleQueue { private: struct SimpleQueueEntry { std::atomic_bool ready{false}; SimpleQueueEntry* next; T value; }; std::atomic head{nullptr}; SimpleQueueEntry* tail = nullptr; public: SimpleQueue(); //Used by single queue thread (i.e. EE) void Enqueue(T entry); //Used by single worker thread (i.e. IO) bool Dequeue(T* entry); //May return false negative when another thread is mid Queue() //Intended to only be used from queue thread bool IsQueueEmpty(); ~SimpleQueue(); }; template SimpleQueue::SimpleQueue() { tail = new SimpleQueueEntry(); head.store(tail); } template void SimpleQueue::Enqueue(T entry) { //Allocate Next entry, and assign to head SimpleQueueEntry* newHead = new SimpleQueueEntry(); SimpleQueueEntry* newEntry = head.exchange(newHead); //Fill in newEntry->value = std::move(entry); newEntry->next = newHead; //Set ready (can be dequeued) newEntry->ready.store(true); } template bool SimpleQueue::Dequeue(T* entry) { if (!tail->ready.load()) return false; SimpleQueueEntry* retEntry = tail; tail = retEntry->next; *entry = std::move(retEntry->value); delete retEntry; return true; } //Note, next entry may not be ready to dequeue template bool SimpleQueue::IsQueueEmpty() { return head.load() == tail; } template SimpleQueue::~SimpleQueue() { if (head != nullptr) { if (!IsQueueEmpty()) { Console.Error("DEV9: Queue not empty"); pxAssert(false); //Empty Queue T entry; while (!IsQueueEmpty()) Dequeue(&entry); } delete head; head = nullptr; tail = nullptr; } }