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.
This commit is contained in:
committed by
Nathaniel Wesley Filardo
parent
e25db7b832
commit
06e333a3a9
@@ -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<capptr::bounds::AllocFull> p,
|
||||
CapPtr<void, capptr::bounds::AllocFull> 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<capptr::bounds::AllocFull> 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;
|
||||
}
|
||||
|
||||
@@ -127,31 +127,40 @@ namespace snmalloc
|
||||
#endif
|
||||
|
||||
public:
|
||||
QueuePtr<BQueue> atomic_read_next(const FreeListKey& key)
|
||||
template<
|
||||
SNMALLOC_CONCEPT(capptr::ConceptBound) BView = typename BQueue::
|
||||
template with_wildness<capptr::dimension::Wildness::Tame>,
|
||||
typename Domesticator>
|
||||
HeadPtr<BView, BQueue>
|
||||
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<BQueue> read_next(const FreeListKey& key)
|
||||
template<
|
||||
SNMALLOC_CONCEPT(capptr::ConceptBound) BView = typename BQueue::
|
||||
template with_wildness<capptr::dimension::Wildness::Tame>,
|
||||
typename Domesticator>
|
||||
HeadPtr<BView, BQueue>
|
||||
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<BView, BQueue> take(const FreeListKey& key)
|
||||
{
|
||||
auto c = curr;
|
||||
auto next = curr->read_next(key);
|
||||
// TODO: Placeholder
|
||||
auto domesticate = [](FreeObject::QueuePtr<BQueue> p)
|
||||
SNMALLOC_FAST_PATH_LAMBDA { return p; };
|
||||
auto next = curr->read_next(key, domesticate);
|
||||
|
||||
Aal::prefetch(next.unsafe_ptr());
|
||||
curr = next;
|
||||
|
||||
@@ -102,13 +102,18 @@ namespace snmalloc
|
||||
/**
|
||||
* Returns the front message, or null if not possible to return a message.
|
||||
*/
|
||||
std::pair<FreeObject::QueuePtr<capptr::bounds::AllocFull>, bool>
|
||||
std::pair<
|
||||
FreeObject::HeadPtr<capptr::bounds::AllocFull, capptr::bounds::AllocFull>,
|
||||
bool>
|
||||
dequeue(const FreeListKey& key)
|
||||
{
|
||||
auto domesticate = [](FreeObject::QueuePtr<capptr::bounds::AllocFull> p)
|
||||
SNMALLOC_FAST_PATH_LAMBDA { return p; };
|
||||
invariant();
|
||||
FreeObject::QueuePtr<capptr::bounds::AllocFull> first = front;
|
||||
FreeObject::HeadPtr<capptr::bounds::AllocFull, capptr::bounds::AllocFull>
|
||||
first = domesticate(front);
|
||||
FreeObject::QueuePtr<capptr::bounds::AllocFull> next =
|
||||
first->atomic_read_next(key);
|
||||
first->atomic_read_next(key, domesticate);
|
||||
|
||||
if (next != nullptr)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user