From 06e333a3a9d4d3cf611ef2df541909910306a67f Mon Sep 17 00:00:00 2001 From: Nathaniel Wesley Filardo Date: Tue, 28 Sep 2021 12:49:48 +0100 Subject: [PATCH] NFC: FreeObject: shift readers to take domestication callbacks If we're going to check next's prev in atomic_read_next, we will need to domesticate the next pointer first. We could push the check up, but that opens boxes, so it's simpler to plumb domestication this far down. For symmetry, we also plumb to (non-atomic) read_next. --- src/mem/corealloc.h | 11 ++++++--- src/mem/freelist.h | 52 +++++++++++++++++++++++++++------------ src/mem/remoteallocator.h | 11 ++++++--- 3 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/mem/corealloc.h b/src/mem/corealloc.h index 7870d73..ecc01b0 100644 --- a/src/mem/corealloc.h +++ b/src/mem/corealloc.h @@ -416,7 +416,7 @@ namespace snmalloc #ifdef SNMALLOC_TRACING std::cout << "Handling remote" << std::endl; #endif - handle_dealloc_remote(entry, p, need_post); + handle_dealloc_remote(entry, r.first.as_void(), need_post); } if (need_post) @@ -435,7 +435,7 @@ namespace snmalloc */ void handle_dealloc_remote( const MetaEntry& entry, - FreeObject::QueuePtr p, + CapPtr p, bool& need_post) { // TODO this needs to not double count stats @@ -716,6 +716,9 @@ namespace snmalloc bool flush(bool destroy_queue = false) { SNMALLOC_ASSERT(attached_cache != nullptr); + // TODO: Placeholder + auto domesticate = [](FreeObject::QueuePtr p) + SNMALLOC_FAST_PATH_LAMBDA { return p; }; if (destroy_queue) { @@ -724,10 +727,10 @@ namespace snmalloc while (p != nullptr) { bool need_post = true; // Always going to post, so ignore. - auto n = p->atomic_read_next(key_global); + auto n = p->atomic_read_next(key_global, domesticate); auto& entry = SharedStateHandle::Pagemap::get_metaentry( backend_state_ptr(), snmalloc::address_cast(p)); - handle_dealloc_remote(entry, p, need_post); + handle_dealloc_remote(entry, p.as_void(), need_post); // XXX n is not known to be domesticated p = n; } diff --git a/src/mem/freelist.h b/src/mem/freelist.h index dd15f10..0b882a3 100644 --- a/src/mem/freelist.h +++ b/src/mem/freelist.h @@ -127,31 +127,40 @@ namespace snmalloc #endif public: - QueuePtr atomic_read_next(const FreeListKey& key) + template< + SNMALLOC_CONCEPT(capptr::ConceptBound) BView = typename BQueue:: + template with_wildness, + typename Domesticator> + HeadPtr + atomic_read_next(const FreeListKey& key, Domesticator domesticate) { - auto n = FreeObject::decode_next( + auto n_wild = FreeObject::decode_next( address_cast(&this->next_object), this->atomic_next_object.load(std::memory_order_acquire), key); + auto n_tame = domesticate(n_wild); #ifdef SNMALLOC_CHECK_CLIENT - // XXX n is not known to be domesticated here - if (n != nullptr) + if (n_tame != nullptr) { - n->check_prev(signed_prev(address_cast(this), address_cast(n), key)); + n_tame->check_prev( + signed_prev(address_cast(this), address_cast(n_tame), key)); } -#else - UNUSED(key); #endif - return n; + return n_tame; } /** * Read the next pointer */ - QueuePtr read_next(const FreeListKey& key) + template< + SNMALLOC_CONCEPT(capptr::ConceptBound) BView = typename BQueue:: + template with_wildness, + typename Domesticator> + HeadPtr + read_next(const FreeListKey& key, Domesticator domesticate) { - return FreeObject::decode_next( - address_cast(&this->next_object), this->next_object, key); + return domesticate(FreeObject::decode_next( + address_cast(&this->next_object), this->next_object, key)); } /** @@ -228,10 +237,18 @@ namespace snmalloc } /** - * Decode next. While traversing a queue, BView and BQueue here will - * often be equal (i.e., CBAllocExportWild) rather than dichotomous. - * However, we do occasionally decode an actual head pointer, so be - * polymorphic here. + * Decode next. While traversing a queue, BView and BQueue here will often + * be equal (i.e., CBAllocExportWild) rather than dichotomous. However, + * we do occasionally decode an actual head pointer, so be polymorphic here. + * + * TODO: We'd like, in some sense, to more tightly couple or integrate this + * into to the domestication process. We could introduce an additional + * state in the capptr_bounds::wild taxonomy (e.g, Obfuscated) so that the + * Domesticator-s below have to call through this function to get the Wild + * pointer they can then make Tame. It's not yet entirely clear what that + * would look like and whether/how the encode_next side of things should be + * exposed. For the moment, obfuscation is left encapsulated within + * FreeObject and we do not capture any of it statically. */ template< SNMALLOC_CONCEPT(capptr::ConceptBound) BView, @@ -391,7 +408,10 @@ namespace snmalloc FreeObject::HeadPtr take(const FreeListKey& key) { auto c = curr; - auto next = curr->read_next(key); + // TODO: Placeholder + auto domesticate = [](FreeObject::QueuePtr p) + SNMALLOC_FAST_PATH_LAMBDA { return p; }; + auto next = curr->read_next(key, domesticate); Aal::prefetch(next.unsafe_ptr()); curr = next; diff --git a/src/mem/remoteallocator.h b/src/mem/remoteallocator.h index 2e4e735..2be554f 100644 --- a/src/mem/remoteallocator.h +++ b/src/mem/remoteallocator.h @@ -102,13 +102,18 @@ namespace snmalloc /** * Returns the front message, or null if not possible to return a message. */ - std::pair, bool> + std::pair< + FreeObject::HeadPtr, + bool> dequeue(const FreeListKey& key) { + auto domesticate = [](FreeObject::QueuePtr p) + SNMALLOC_FAST_PATH_LAMBDA { return p; }; invariant(); - FreeObject::QueuePtr first = front; + FreeObject::HeadPtr + first = domesticate(front); FreeObject::QueuePtr next = - first->atomic_read_next(key); + first->atomic_read_next(key, domesticate); if (next != nullptr) {