NFC: MPMCStack: prepare for pointer wrappers

This commit is contained in:
Nathaniel Filardo
2021-03-10 19:32:47 +00:00
committed by Matthew Parkinson
parent ed615eade9
commit ebc02a141e
4 changed files with 52 additions and 27 deletions

View File

@@ -1,6 +1,7 @@
#pragma once
#include "bits.h"
#include "ptrwrap.h"
/**
* This file contains an abstraction of ABA protection. This API should be
@@ -23,19 +24,23 @@ namespace snmalloc
// fall back to locked implementation.
#if defined(PLATFORM_IS_X86) && \
!(defined(GCC_NOT_CLANG) && defined(OPEN_ENCLAVE))
template<typename T, Construction c = RequiresInit>
template<
typename T,
Construction c = RequiresInit,
template<typename> typename Ptr = Pointer,
template<typename> typename AtomicPtr = AtomicPointer>
class ABA
{
public:
struct alignas(2 * sizeof(std::size_t)) Linked
{
T* ptr;
Ptr<T> ptr;
uintptr_t aba;
};
struct Independent
{
std::atomic<T*> ptr;
AtomicPtr<T> ptr;
std::atomic<uintptr_t> aba;
};
@@ -60,7 +65,7 @@ namespace snmalloc
init(nullptr);
}
void init(T* x)
void init(Ptr<T> x)
{
independent.ptr.store(x, std::memory_order_relaxed);
independent.aba.store(0, std::memory_order_relaxed);
@@ -92,18 +97,18 @@ namespace snmalloc
*/
Cmp(Linked old, ABA* parent) : old(old), parent(parent) {}
T* ptr()
Ptr<T> ptr()
{
return old.ptr;
}
bool store_conditional(T* value)
bool store_conditional(Ptr<T> value)
{
# if defined(_MSC_VER) && defined(SNMALLOC_VA_BITS_64)
auto result = _InterlockedCompareExchange128(
(volatile __int64*)parent,
(__int64)(old.aba + (uintptr_t)1),
(__int64)value,
(__int64)address_cast(value),
(__int64*)&old);
# else
# if defined(__GNUC__) && defined(SNMALLOC_VA_BITS_64) && \
@@ -132,7 +137,7 @@ namespace snmalloc
};
// This method is used in Verona
T* peek()
Ptr<T> peek()
{
return independent.ptr.load(std::memory_order_relaxed);
}
@@ -141,10 +146,14 @@ namespace snmalloc
/**
* Naive implementation of ABA protection using a spin lock.
*/
template<typename T, Construction c = RequiresInit>
template<
typename T,
Construction c = RequiresInit,
template<typename> typename Ptr = Pointer,
template<typename> typename AtomicPtr = AtomicPointer>
class ABA
{
std::atomic<T*> ptr = nullptr;
AtomicPtr<T> ptr = nullptr;
std::atomic_flag lock = ATOMIC_FLAG_INIT;
public:
@@ -169,12 +178,12 @@ namespace snmalloc
ABA* parent;
public:
T* ptr()
Ptr<T> ptr()
{
return parent->ptr;
}
bool store_conditional(T* t)
bool store_conditional(Ptr<T> t)
{
parent->ptr = t;
return true;
@@ -190,7 +199,7 @@ namespace snmalloc
};
// This method is used in Verona
T* peek()
Ptr<T> peek()
{
return ptr.load(std::memory_order_relaxed);
}

View File

@@ -4,43 +4,47 @@
namespace snmalloc
{
template<class T, Construction c = RequiresInit>
template<
class T,
Construction c = RequiresInit,
template<typename> typename Ptr = Pointer,
template<typename> typename AtomicPtr = AtomicPointer>
class MPMCStack
{
using ABAT = ABA<T, c>;
using ABAT = ABA<T, c, Ptr, AtomicPtr>;
private:
static_assert(
std::is_same<decltype(T::next), std::atomic<T*>>::value,
"T->next must be a std::atomic<T*>");
std::is_same<decltype(T::next), AtomicPtr<T>>::value,
"T->next must be an AtomicPtr<T>");
ABAT stack;
public:
void push(T* item)
void push(Ptr<T> item)
{
return push(item, item);
}
void push(T* first, T* last)
void push(Ptr<T> first, Ptr<T> last)
{
// Pushes an item on the stack.
auto cmp = stack.read();
do
{
T* top = cmp.ptr();
Ptr<T> top = cmp.ptr();
last->next.store(top, std::memory_order_release);
} while (!cmp.store_conditional(first));
}
T* pop()
Ptr<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;
Ptr<T> top;
Ptr<T> next;
do
{
@@ -55,11 +59,11 @@ namespace snmalloc
return top;
}
T* pop_all()
Ptr<T> pop_all()
{
// Returns all items as a linked list, leaving an empty stack.
auto cmp = stack.read();
T* top;
Ptr<T> top;
do
{

View File

@@ -22,7 +22,13 @@ namespace snmalloc
// This is the view of a contiguous memory area when it is being kept
// in the global size-classed caches of available contiguous memory areas.
private:
template<class a, Construction c>
template<
class a,
Construction c,
template<typename>
typename P,
template<typename>
typename AP>
friend class MPMCStack;
template<SNMALLOC_CONCEPT(ConceptPAL) PAL>
friend class MemoryProviderStateMixin;

View File

@@ -10,7 +10,13 @@ namespace snmalloc
private:
template<class TT, class MemoryProvider>
friend class Pool;
template<class TT, Construction c>
template<
class a,
Construction c,
template<typename>
typename P,
template<typename>
typename AP>
friend class MPMCStack;
/// Used by the pool for chaining together entries when not in use.