#pragma once #include "aba.h" #include "ptrwrap.h" namespace snmalloc { template class MPMCStack { using ABAT = ABA; private: ABAT stack; public: constexpr MPMCStack() = default; void push(T* item) { static_assert( std::is_same>::value, "T->next must be an std::atomic"); return push(item, item); } void push(T* first, T* last) { // Pushes an item on the stack. auto cmp = stack.read(); do { auto top = cmp.ptr(); last->next.store(top, std::memory_order_release); } while (!cmp.store_conditional(first)); } T* pop() { // Returns the next item. If the returned value is decommitted, it is // possible for the read of top->next to segfault. auto cmp = stack.read(); T* top; T* next; do { top = cmp.ptr(); if (top == nullptr) break; next = top->next.load(std::memory_order_acquire); } while (!cmp.store_conditional(next)); return top; } T* pop_all() { // Returns all items as a linked list, leaving an empty stack. auto cmp = stack.read(); T* top; do { top = cmp.ptr(); if (top == nullptr) break; } while (!cmp.store_conditional(nullptr)); return top; } }; } // namespace snmalloc