Overhaul CapPtr

* Switch to a multidimensional taxonomy.

  Rather than encoding the abstract bound states in a single enum, move to a
  more algebraic treatment.  The dimensions themselves are within the
  snmalloc::capptr_bounds namespace so that their fairly generic names do not
  conflict with consumer code.  Aliases for many points in the space are
  established outside that namespace for ease of use elsewhere.

* Introduce several new namespaces:

    * snmalloc::capptr::dimension holds each of the dimension enums

    * snmalloc::capptr holds the bound<> type itself and a ConceptBound

    * snmalloc::capptr::bounds gives convenient specializations of bound<>

    * snmalloc::capptr also has aliases for CapPtr<> itself

  All told, rather than `CapPtr<T, CBChunk>`, we now expect client code to read
  `capptr::Chunk<T>` in almost all cases (and this is just an alias for the
  appropriate `CapPtr<T, bounds<...>>` type).  When the bound<>s themselves are
  necessary, as when calling capptr_bound, we expect that they will almost
  always be pronounced using an alias (e.g., `capptr::bounds::Alloc`).

* Chase consequences.

* Prune old taxa and aliases that are no longer in use in snmalloc2.
This commit is contained in:
Nathaniel Wesley Filardo
2021-07-19 09:49:18 +01:00
committed by Nathaniel Wesley Filardo
parent b57390663e
commit 9065893181
17 changed files with 399 additions and 348 deletions

View File

@@ -35,10 +35,10 @@ namespace snmalloc
// Store the message queue on a separate cacheline. It is mutable data that
// is read by other threads.
alignas(CACHELINE_SIZE) AtomicCapPtr<FreeObject, CBAlloc> back{nullptr};
alignas(CACHELINE_SIZE) capptr::AtomicAllocFull<FreeObject> back{nullptr};
// Store the two ends on different cache lines as access by different
// threads.
alignas(CACHELINE_SIZE) CapPtr<FreeObject, CBAlloc> front{nullptr};
alignas(CACHELINE_SIZE) capptr::AllocFull<FreeObject> front{nullptr};
constexpr RemoteAllocator() = default;
@@ -48,7 +48,7 @@ namespace snmalloc
SNMALLOC_ASSERT(front != nullptr);
}
void init(CapPtr<FreeObject, CBAlloc> stub)
void init(capptr::AllocFull<FreeObject> stub)
{
stub->atomic_store_null(key_global);
front = stub;
@@ -56,9 +56,9 @@ namespace snmalloc
invariant();
}
CapPtr<FreeObject, CBAlloc> destroy()
capptr::AllocFull<FreeObject> destroy()
{
CapPtr<FreeObject, CBAlloc> fnt = front;
capptr::AllocFull<FreeObject> fnt = front;
back.store(nullptr, std::memory_order_relaxed);
front = nullptr;
return fnt;
@@ -66,7 +66,7 @@ namespace snmalloc
inline bool is_empty()
{
CapPtr<FreeObject, CBAlloc> bk = back.load(std::memory_order_relaxed);
capptr::AllocFull<FreeObject> bk = back.load(std::memory_order_relaxed);
return bk == front;
}
@@ -76,21 +76,21 @@ namespace snmalloc
* last should be linked together through their next pointers.
*/
void enqueue(
CapPtr<FreeObject, CBAlloc> first,
CapPtr<FreeObject, CBAlloc> last,
capptr::AllocFull<FreeObject> first,
capptr::AllocFull<FreeObject> last,
const FreeListKey& key)
{
invariant();
last->atomic_store_null(key);
// exchange needs to be a release, so nullptr in next is visible.
CapPtr<FreeObject, CBAlloc> prev =
capptr::AllocFull<FreeObject> prev =
back.exchange(last, std::memory_order_release);
prev->atomic_store_next(first, key);
}
CapPtr<FreeObject, CBAlloc> peek()
capptr::AllocFull<FreeObject> peek()
{
return front;
}
@@ -98,11 +98,12 @@ namespace snmalloc
/**
* Returns the front message, or null if not possible to return a message.
*/
std::pair<CapPtr<FreeObject, CBAlloc>, bool> dequeue(const FreeListKey& key)
std::pair<capptr::AllocFull<FreeObject>, bool>
dequeue(const FreeListKey& key)
{
invariant();
CapPtr<FreeObject, CBAlloc> first = front;
CapPtr<FreeObject, CBAlloc> next = first->atomic_read_next(key);
capptr::AllocFull<FreeObject> first = front;
capptr::AllocFull<FreeObject> next = first->atomic_read_next(key);
if (next != nullptr)
{