CapPtr: shift free lists to Alloc bounds
This is incomplete, yet still more reflective of what's going on: we take the exported pointers back from userspace and thread them directly into the free lists. So: move capptr_to_user_address_control to list construction time rather than list consumption time.
This commit is contained in:
committed by
Nathaniel Wesley Filardo
parent
55cd5e87c0
commit
7e53a2e82a
@@ -162,8 +162,8 @@ namespace snmalloc
|
|||||||
// Manufacture an allocation to prime the queue
|
// Manufacture an allocation to prime the queue
|
||||||
// Using an actual allocation removes a conditional from a critical path.
|
// Using an actual allocation removes a conditional from a critical path.
|
||||||
auto dummy =
|
auto dummy =
|
||||||
capptr::AllocFull<void>(small_alloc_one(MIN_ALLOC_SIZE))
|
capptr::Alloc<void>(small_alloc_one(MIN_ALLOC_SIZE))
|
||||||
.template as_static<FreeObject::T<capptr::bounds::AllocFull>>();
|
.template as_static<FreeObject::T<capptr::bounds::Alloc>>();
|
||||||
if (dummy == nullptr)
|
if (dummy == nullptr)
|
||||||
{
|
{
|
||||||
error("Critical error: Out-of-memory during initialisation.");
|
error("Critical error: Out-of-memory during initialisation.");
|
||||||
@@ -185,8 +185,9 @@ namespace snmalloc
|
|||||||
size,
|
size,
|
||||||
[&](
|
[&](
|
||||||
sizeclass_t sizeclass,
|
sizeclass_t sizeclass,
|
||||||
FreeListIter<capptr::bounds::AllocFull, capptr::bounds::AllocFull>*
|
FreeListIter<capptr::bounds::Alloc, capptr::bounds::Alloc>* fl) {
|
||||||
fl) { return small_alloc<NoZero>(sizeclass, *fl); });
|
return small_alloc<NoZero>(sizeclass, *fl);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static SNMALLOC_FAST_PATH void alloc_new_list(
|
static SNMALLOC_FAST_PATH void alloc_new_list(
|
||||||
@@ -248,7 +249,8 @@ namespace snmalloc
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
b.add(
|
b.add(
|
||||||
FreeObject::make<capptr::bounds::AllocFull>(curr_ptr.as_void()),
|
FreeObject::make<capptr::bounds::Alloc>(
|
||||||
|
capptr_to_user_address_control(curr_ptr.as_void())),
|
||||||
key,
|
key,
|
||||||
entropy);
|
entropy);
|
||||||
curr_ptr = curr_ptr->next;
|
curr_ptr = curr_ptr->next;
|
||||||
@@ -258,9 +260,10 @@ namespace snmalloc
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
b.add(
|
b.add(
|
||||||
Aal::capptr_bound<
|
FreeObject::make<capptr::bounds::Alloc>(
|
||||||
FreeObject::T<capptr::bounds::AllocFull>,
|
capptr_to_user_address_control(
|
||||||
capptr::bounds::AllocFull>(p, rsize),
|
Aal::capptr_bound<void, capptr::bounds::AllocFull>(
|
||||||
|
p.as_void(), rsize))),
|
||||||
key);
|
key);
|
||||||
p = pointer_offset(p, rsize);
|
p = pointer_offset(p, rsize);
|
||||||
} while (p < slab_end);
|
} while (p < slab_end);
|
||||||
@@ -272,7 +275,7 @@ namespace snmalloc
|
|||||||
ChunkRecord* clear_slab(Metaslab* meta, sizeclass_t sizeclass)
|
ChunkRecord* clear_slab(Metaslab* meta, sizeclass_t sizeclass)
|
||||||
{
|
{
|
||||||
auto& key = entropy.get_free_list_key();
|
auto& key = entropy.get_free_list_key();
|
||||||
FreeListIter<capptr::bounds::AllocFull, capptr::bounds::AllocFull> fl;
|
FreeListIter<capptr::bounds::Alloc, capptr::bounds::Alloc> fl;
|
||||||
auto more = meta->free_queue.close(fl, key);
|
auto more = meta->free_queue.close(fl, key);
|
||||||
UNUSED(more);
|
UNUSED(more);
|
||||||
void* p = finish_alloc_no_zero(fl.take(key), sizeclass);
|
void* p = finish_alloc_no_zero(fl.take(key), sizeclass);
|
||||||
@@ -435,7 +438,7 @@ namespace snmalloc
|
|||||||
*/
|
*/
|
||||||
void handle_dealloc_remote(
|
void handle_dealloc_remote(
|
||||||
const MetaEntry& entry,
|
const MetaEntry& entry,
|
||||||
CapPtr<void, capptr::bounds::AllocFull> p,
|
CapPtr<void, capptr::bounds::Alloc> p,
|
||||||
bool& need_post)
|
bool& need_post)
|
||||||
{
|
{
|
||||||
// TODO this needs to not double count stats
|
// TODO this needs to not double count stats
|
||||||
@@ -444,7 +447,7 @@ namespace snmalloc
|
|||||||
|
|
||||||
if (likely(entry.get_remote() == public_state()))
|
if (likely(entry.get_remote() == public_state()))
|
||||||
{
|
{
|
||||||
if (likely(dealloc_local_object_fast(entry, p.unsafe_ptr(), entropy)))
|
if (likely(dealloc_local_object_fast(entry, p.as_void(), entropy)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dealloc_local_object_slow(entry);
|
dealloc_local_object_slow(entry);
|
||||||
@@ -569,7 +572,8 @@ namespace snmalloc
|
|||||||
return handle_message_queue_inner(action, args...);
|
return handle_message_queue_inner(action, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
SNMALLOC_FAST_PATH void dealloc_local_object(void* p)
|
SNMALLOC_FAST_PATH void
|
||||||
|
dealloc_local_object(CapPtr<void, capptr::bounds::Alloc> p)
|
||||||
{
|
{
|
||||||
auto entry = SharedStateHandle::Pagemap::get_metaentry(
|
auto entry = SharedStateHandle::Pagemap::get_metaentry(
|
||||||
backend_state_ptr(), snmalloc::address_cast(p));
|
backend_state_ptr(), snmalloc::address_cast(p));
|
||||||
@@ -580,7 +584,9 @@ namespace snmalloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
SNMALLOC_FAST_PATH static bool dealloc_local_object_fast(
|
SNMALLOC_FAST_PATH static bool dealloc_local_object_fast(
|
||||||
const MetaEntry& entry, void* p, LocalEntropy& entropy)
|
const MetaEntry& entry,
|
||||||
|
CapPtr<void, capptr::bounds::Alloc> p,
|
||||||
|
LocalEntropy& entropy)
|
||||||
{
|
{
|
||||||
auto meta = entry.get_metaslab();
|
auto meta = entry.get_metaslab();
|
||||||
|
|
||||||
@@ -590,8 +596,7 @@ namespace snmalloc
|
|||||||
Metaslab::is_start_of_object(entry.get_sizeclass(), address_cast(p)),
|
Metaslab::is_start_of_object(entry.get_sizeclass(), address_cast(p)),
|
||||||
"Not deallocating start of an object");
|
"Not deallocating start of an object");
|
||||||
|
|
||||||
auto cp = FreeObject::QueuePtr<capptr::bounds::AllocFull>(
|
auto cp = p.as_static<FreeObject::T<capptr::bounds::Alloc>>();
|
||||||
reinterpret_cast<FreeObject::T<capptr::bounds::AllocFull>*>(p));
|
|
||||||
|
|
||||||
auto& key = entropy.get_free_list_key();
|
auto& key = entropy.get_free_list_key();
|
||||||
|
|
||||||
@@ -604,7 +609,7 @@ namespace snmalloc
|
|||||||
template<ZeroMem zero_mem>
|
template<ZeroMem zero_mem>
|
||||||
SNMALLOC_SLOW_PATH void* small_alloc(
|
SNMALLOC_SLOW_PATH void* small_alloc(
|
||||||
sizeclass_t sizeclass,
|
sizeclass_t sizeclass,
|
||||||
FreeListIter<capptr::bounds::AllocFull, capptr::bounds::AllocFull>&
|
FreeListIter<capptr::bounds::Alloc, capptr::bounds::Alloc>&
|
||||||
fast_free_list)
|
fast_free_list)
|
||||||
{
|
{
|
||||||
size_t rsize = sizeclass_to_size(sizeclass);
|
size_t rsize = sizeclass_to_size(sizeclass);
|
||||||
@@ -664,7 +669,7 @@ namespace snmalloc
|
|||||||
template<ZeroMem zero_mem>
|
template<ZeroMem zero_mem>
|
||||||
SNMALLOC_SLOW_PATH void* small_alloc_slow(
|
SNMALLOC_SLOW_PATH void* small_alloc_slow(
|
||||||
sizeclass_t sizeclass,
|
sizeclass_t sizeclass,
|
||||||
FreeListIter<capptr::bounds::AllocFull, capptr::bounds::AllocFull>&
|
FreeListIter<capptr::bounds::Alloc, capptr::bounds::Alloc>&
|
||||||
fast_free_list,
|
fast_free_list,
|
||||||
size_t rsize)
|
size_t rsize)
|
||||||
{
|
{
|
||||||
@@ -717,7 +722,7 @@ namespace snmalloc
|
|||||||
{
|
{
|
||||||
SNMALLOC_ASSERT(attached_cache != nullptr);
|
SNMALLOC_ASSERT(attached_cache != nullptr);
|
||||||
// TODO: Placeholder
|
// TODO: Placeholder
|
||||||
auto domesticate = [](FreeObject::QueuePtr<capptr::bounds::AllocFull> p)
|
auto domesticate = [](FreeObject::QueuePtr<capptr::bounds::Alloc> p)
|
||||||
SNMALLOC_FAST_PATH_LAMBDA { return p; };
|
SNMALLOC_FAST_PATH_LAMBDA { return p; };
|
||||||
|
|
||||||
if (destroy_queue)
|
if (destroy_queue)
|
||||||
|
|||||||
@@ -249,8 +249,8 @@ namespace snmalloc
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode next. While traversing a queue, BView and BQueue here will often
|
* Decode next. While traversing a queue, BView and BQueue here will often
|
||||||
* be equal (i.e., CBAllocExportWild) rather than dichotomous. However,
|
* be equal (i.e., AllocUserWild) rather than dichotomous. However, we do
|
||||||
* we do occasionally decode an actual head pointer, so be polymorphic here.
|
* occasionally decode an actual head pointer, so be polymorphic here.
|
||||||
*
|
*
|
||||||
* TODO: We'd like, in some sense, to more tightly couple or integrate this
|
* TODO: We'd like, in some sense, to more tightly couple or integrate this
|
||||||
* into to the domestication process. We could introduce an additional
|
* into to the domestication process. We could introduce an additional
|
||||||
|
|||||||
@@ -214,30 +214,29 @@ namespace snmalloc
|
|||||||
auto slowpath =
|
auto slowpath =
|
||||||
[&](
|
[&](
|
||||||
sizeclass_t sizeclass,
|
sizeclass_t sizeclass,
|
||||||
FreeListIter<capptr::bounds::AllocFull, capptr::bounds::AllocFull>*
|
FreeListIter<capptr::bounds::Alloc, capptr::bounds::Alloc>* fl)
|
||||||
fl) SNMALLOC_FAST_PATH_LAMBDA {
|
SNMALLOC_FAST_PATH_LAMBDA {
|
||||||
if (likely(core_alloc != nullptr))
|
if (likely(core_alloc != nullptr))
|
||||||
{
|
{
|
||||||
return core_alloc->handle_message_queue(
|
return core_alloc->handle_message_queue(
|
||||||
[](
|
[](
|
||||||
CoreAlloc* core_alloc,
|
CoreAlloc* core_alloc,
|
||||||
sizeclass_t sizeclass,
|
sizeclass_t sizeclass,
|
||||||
FreeListIter<
|
FreeListIter<capptr::bounds::Alloc, capptr::bounds::Alloc>*
|
||||||
capptr::bounds::AllocFull,
|
fl) {
|
||||||
capptr::bounds::AllocFull>* fl) {
|
return core_alloc->template small_alloc<zero_mem>(
|
||||||
return core_alloc->template small_alloc<zero_mem>(
|
sizeclass, *fl);
|
||||||
sizeclass, *fl);
|
},
|
||||||
|
core_alloc,
|
||||||
|
sizeclass,
|
||||||
|
fl);
|
||||||
|
}
|
||||||
|
return lazy_init(
|
||||||
|
[&](CoreAlloc*, sizeclass_t sizeclass) {
|
||||||
|
return small_alloc<zero_mem>(sizeclass_to_size(sizeclass));
|
||||||
},
|
},
|
||||||
core_alloc,
|
sizeclass);
|
||||||
sizeclass,
|
};
|
||||||
fl);
|
|
||||||
}
|
|
||||||
return lazy_init(
|
|
||||||
[&](CoreAlloc*, sizeclass_t sizeclass) {
|
|
||||||
return small_alloc<zero_mem>(sizeclass_to_size(sizeclass));
|
|
||||||
},
|
|
||||||
sizeclass);
|
|
||||||
};
|
|
||||||
|
|
||||||
return local_cache.template alloc<zero_mem, SharedStateHandle>(
|
return local_cache.template alloc<zero_mem, SharedStateHandle>(
|
||||||
size, slowpath);
|
size, slowpath);
|
||||||
@@ -260,20 +259,18 @@ namespace snmalloc
|
|||||||
* In the second case we need to recheck if this is a remote deallocation,
|
* In the second case we need to recheck if this is a remote deallocation,
|
||||||
* as we might acquire the originating allocator.
|
* as we might acquire the originating allocator.
|
||||||
*/
|
*/
|
||||||
SNMALLOC_SLOW_PATH void dealloc_remote_slow(void* p)
|
SNMALLOC_SLOW_PATH void dealloc_remote_slow(capptr::Alloc<void> p)
|
||||||
{
|
{
|
||||||
if (core_alloc != nullptr)
|
if (core_alloc != nullptr)
|
||||||
{
|
{
|
||||||
#ifdef SNMALLOC_TRACING
|
#ifdef SNMALLOC_TRACING
|
||||||
std::cout << "Remote dealloc post" << p << " size " << alloc_size(p)
|
std::cout << "Remote dealloc post" << p.unsafe_ptr() << " size "
|
||||||
<< std::endl;
|
<< alloc_size(p.unsafe_ptr()) << std::endl;
|
||||||
#endif
|
#endif
|
||||||
MetaEntry entry = SharedStateHandle::Pagemap::get_metaentry(
|
MetaEntry entry = SharedStateHandle::Pagemap::get_metaentry(
|
||||||
core_alloc->backend_state_ptr(), address_cast(p));
|
core_alloc->backend_state_ptr(), address_cast(p));
|
||||||
local_cache.remote_dealloc_cache.template dealloc<sizeof(CoreAlloc)>(
|
local_cache.remote_dealloc_cache.template dealloc<sizeof(CoreAlloc)>(
|
||||||
entry.get_remote()->trunc_id(),
|
entry.get_remote()->trunc_id(), p, key_global);
|
||||||
capptr::AllocFull<void>(p),
|
|
||||||
key_global);
|
|
||||||
post_remote_cache();
|
post_remote_cache();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -281,8 +278,8 @@ namespace snmalloc
|
|||||||
// Recheck what kind of dealloc we should do incase, the allocator we get
|
// Recheck what kind of dealloc we should do incase, the allocator we get
|
||||||
// from lazy_init is the originating allocator.
|
// from lazy_init is the originating allocator.
|
||||||
lazy_init(
|
lazy_init(
|
||||||
[&](CoreAlloc*, void* p) {
|
[&](CoreAlloc*, CapPtr<void, capptr::bounds::Alloc> p) {
|
||||||
dealloc(p); // TODO don't double count statistics
|
dealloc(p.unsafe_ptr()); // TODO don't double count statistics
|
||||||
return nullptr;
|
return nullptr;
|
||||||
},
|
},
|
||||||
p);
|
p);
|
||||||
@@ -450,10 +447,10 @@ namespace snmalloc
|
|||||||
return alloc<zero_mem>(size);
|
return alloc<zero_mem>(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
SNMALLOC_FAST_PATH void dealloc(void* p)
|
SNMALLOC_FAST_PATH void dealloc(void* p_raw)
|
||||||
{
|
{
|
||||||
#ifdef SNMALLOC_PASS_THROUGH
|
#ifdef SNMALLOC_PASS_THROUGH
|
||||||
external_alloc::free(p);
|
external_alloc::free(p_raw);
|
||||||
#else
|
#else
|
||||||
// TODO:
|
// TODO:
|
||||||
// Care is needed so that dealloc(nullptr) works before init
|
// Care is needed so that dealloc(nullptr) works before init
|
||||||
@@ -461,6 +458,7 @@ namespace snmalloc
|
|||||||
// before init, that maps null to a remote_deallocator that will never be
|
// before init, that maps null to a remote_deallocator that will never be
|
||||||
// in thread local state.
|
// in thread local state.
|
||||||
|
|
||||||
|
auto p = capptr_from_client(p_raw);
|
||||||
const MetaEntry& entry = SharedStateHandle::Pagemap::get_metaentry(
|
const MetaEntry& entry = SharedStateHandle::Pagemap::get_metaentry(
|
||||||
core_alloc->backend_state_ptr(), address_cast(p));
|
core_alloc->backend_state_ptr(), address_cast(p));
|
||||||
if (likely(local_cache.remote_allocator == entry.get_remote()))
|
if (likely(local_cache.remote_allocator == entry.get_remote()))
|
||||||
@@ -478,12 +476,10 @@ namespace snmalloc
|
|||||||
if (local_cache.remote_dealloc_cache.reserve_space(entry))
|
if (local_cache.remote_dealloc_cache.reserve_space(entry))
|
||||||
{
|
{
|
||||||
local_cache.remote_dealloc_cache.template dealloc<sizeof(CoreAlloc)>(
|
local_cache.remote_dealloc_cache.template dealloc<sizeof(CoreAlloc)>(
|
||||||
entry.get_remote()->trunc_id(),
|
entry.get_remote()->trunc_id(), p, key_global);
|
||||||
capptr::AllocFull<void>(p),
|
|
||||||
key_global);
|
|
||||||
# ifdef SNMALLOC_TRACING
|
# ifdef SNMALLOC_TRACING
|
||||||
std::cout << "Remote dealloc fast" << p << " size " << alloc_size(p)
|
std::cout << "Remote dealloc fast" << p_raw << " size "
|
||||||
<< std::endl;
|
<< alloc_size(p_raw) << std::endl;
|
||||||
# endif
|
# endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -493,7 +489,7 @@ namespace snmalloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Large deallocation or null.
|
// Large deallocation or null.
|
||||||
if (likely(p != nullptr))
|
if (likely(p.unsafe_ptr() != nullptr))
|
||||||
{
|
{
|
||||||
// Check this is managed by this pagemap.
|
// Check this is managed by this pagemap.
|
||||||
check_client(entry.get_sizeclass() != 0, "Not allocated by snmalloc.");
|
check_client(entry.get_sizeclass() != 0, "Not allocated by snmalloc.");
|
||||||
@@ -511,7 +507,14 @@ namespace snmalloc
|
|||||||
# endif
|
# endif
|
||||||
ChunkRecord* slab_record =
|
ChunkRecord* slab_record =
|
||||||
reinterpret_cast<ChunkRecord*>(entry.get_metaslab());
|
reinterpret_cast<ChunkRecord*>(entry.get_metaslab());
|
||||||
slab_record->chunk = capptr::Chunk<void>(p);
|
/*
|
||||||
|
* StrictProvenance TODO: this is a subversive amplification. p is
|
||||||
|
* AllocWild-bounded, but we're coercing it to Chunk-bounded. We
|
||||||
|
* should, instead, not be storing ->chunk here, but should be keeping
|
||||||
|
* a CapPtr<void, Chunk> to this region internally even while it's
|
||||||
|
* allocated.
|
||||||
|
*/
|
||||||
|
slab_record->chunk = capptr::Chunk<void>(p.unsafe_ptr());
|
||||||
check_init(
|
check_init(
|
||||||
[](
|
[](
|
||||||
CoreAlloc* core_alloc,
|
CoreAlloc* core_alloc,
|
||||||
|
|||||||
@@ -13,20 +13,20 @@ namespace snmalloc
|
|||||||
using Stats = AllocStats<NUM_SIZECLASSES, NUM_LARGE_CLASSES>;
|
using Stats = AllocStats<NUM_SIZECLASSES, NUM_LARGE_CLASSES>;
|
||||||
|
|
||||||
inline static SNMALLOC_FAST_PATH void* finish_alloc_no_zero(
|
inline static SNMALLOC_FAST_PATH void* finish_alloc_no_zero(
|
||||||
FreeObject::HeadPtr<capptr::bounds::AllocFull, capptr::bounds::AllocFull> p,
|
FreeObject::HeadPtr<capptr::bounds::Alloc, capptr::bounds::Alloc> p,
|
||||||
sizeclass_t sizeclass)
|
sizeclass_t sizeclass)
|
||||||
{
|
{
|
||||||
SNMALLOC_ASSERT(Metaslab::is_start_of_object(sizeclass, address_cast(p)));
|
SNMALLOC_ASSERT(Metaslab::is_start_of_object(sizeclass, address_cast(p)));
|
||||||
UNUSED(sizeclass);
|
UNUSED(sizeclass);
|
||||||
|
|
||||||
auto r = capptr_reveal(capptr_to_user_address_control(p.as_void()));
|
auto r = capptr_reveal(p.as_void());
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<ZeroMem zero_mem, typename SharedStateHandle>
|
template<ZeroMem zero_mem, typename SharedStateHandle>
|
||||||
inline static SNMALLOC_FAST_PATH void* finish_alloc(
|
inline static SNMALLOC_FAST_PATH void* finish_alloc(
|
||||||
FreeObject::HeadPtr<capptr::bounds::AllocFull, capptr::bounds::AllocFull> p,
|
FreeObject::HeadPtr<capptr::bounds::Alloc, capptr::bounds::Alloc> p,
|
||||||
sizeclass_t sizeclass)
|
sizeclass_t sizeclass)
|
||||||
{
|
{
|
||||||
auto r = finish_alloc_no_zero(p, sizeclass);
|
auto r = finish_alloc_no_zero(p, sizeclass);
|
||||||
@@ -48,7 +48,7 @@ namespace snmalloc
|
|||||||
// Free list per small size class. These are used for
|
// Free list per small size class. These are used for
|
||||||
// allocation on the fast path. This part of the code is inspired by
|
// allocation on the fast path. This part of the code is inspired by
|
||||||
// mimalloc.
|
// mimalloc.
|
||||||
FreeListIter<capptr::bounds::AllocFull, capptr::bounds::AllocFull>
|
FreeListIter<capptr::bounds::Alloc, capptr::bounds::Alloc>
|
||||||
small_fast_free_lists[NUM_SIZECLASSES];
|
small_fast_free_lists[NUM_SIZECLASSES];
|
||||||
|
|
||||||
// This is the entropy for a particular thread.
|
// This is the entropy for a particular thread.
|
||||||
@@ -90,7 +90,8 @@ namespace snmalloc
|
|||||||
while (!small_fast_free_lists[i].empty())
|
while (!small_fast_free_lists[i].empty())
|
||||||
{
|
{
|
||||||
auto p = small_fast_free_lists[i].take(key);
|
auto p = small_fast_free_lists[i].take(key);
|
||||||
dealloc(finish_alloc_no_zero(p, i));
|
SNMALLOC_ASSERT(Metaslab::is_start_of_object(i, address_cast(p)));
|
||||||
|
dealloc(p.as_void());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ namespace snmalloc
|
|||||||
* Data-structure for building the free list for this slab.
|
* Data-structure for building the free list for this slab.
|
||||||
*/
|
*/
|
||||||
#ifdef SNMALLOC_CHECK_CLIENT
|
#ifdef SNMALLOC_CHECK_CLIENT
|
||||||
FreeListBuilder<true, capptr::bounds::AllocFull, capptr::bounds::AllocFull>
|
FreeListBuilder<true, capptr::bounds::Alloc, capptr::bounds::Alloc>
|
||||||
free_queue;
|
free_queue;
|
||||||
#else
|
#else
|
||||||
FreeListBuilder<false, capptr::bounds::AllocFull, capptr::bounds::AllocFull>
|
FreeListBuilder<false, capptr::bounds::Alloc, capptr::bounds::Alloc>
|
||||||
free_queue;
|
free_queue;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -155,10 +155,10 @@ namespace snmalloc
|
|||||||
* available objects for this metaslab.
|
* available objects for this metaslab.
|
||||||
*/
|
*/
|
||||||
static SNMALLOC_FAST_PATH
|
static SNMALLOC_FAST_PATH
|
||||||
std::pair<FreeObject::QueuePtr<capptr::bounds::AllocFull>, bool>
|
std::pair<FreeObject::QueuePtr<capptr::bounds::Alloc>, bool>
|
||||||
alloc_free_list(
|
alloc_free_list(
|
||||||
Metaslab* meta,
|
Metaslab* meta,
|
||||||
FreeListIter<capptr::bounds::AllocFull, capptr::bounds::AllocFull>&
|
FreeListIter<capptr::bounds::Alloc, capptr::bounds::Alloc>&
|
||||||
fast_free_list,
|
fast_free_list,
|
||||||
LocalEntropy& entropy,
|
LocalEntropy& entropy,
|
||||||
sizeclass_t sizeclass)
|
sizeclass_t sizeclass)
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ namespace snmalloc
|
|||||||
// Store the message queue on a separate cacheline. It is mutable data that
|
// Store the message queue on a separate cacheline. It is mutable data that
|
||||||
// is read by other threads.
|
// is read by other threads.
|
||||||
alignas(CACHELINE_SIZE)
|
alignas(CACHELINE_SIZE)
|
||||||
FreeObject::AtomicQueuePtr<capptr::bounds::AllocFull> back{nullptr};
|
FreeObject::AtomicQueuePtr<capptr::bounds::Alloc> back{nullptr};
|
||||||
// Store the two ends on different cache lines as access by different
|
// Store the two ends on different cache lines as access by different
|
||||||
// threads.
|
// threads.
|
||||||
alignas(CACHELINE_SIZE)
|
alignas(CACHELINE_SIZE) FreeObject::QueuePtr<capptr::bounds::Alloc> front{
|
||||||
FreeObject::QueuePtr<capptr::bounds::AllocFull> front{nullptr};
|
nullptr};
|
||||||
|
|
||||||
constexpr RemoteAllocator() = default;
|
constexpr RemoteAllocator() = default;
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ namespace snmalloc
|
|||||||
SNMALLOC_ASSERT(front != nullptr);
|
SNMALLOC_ASSERT(front != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(FreeObject::QueuePtr<capptr::bounds::AllocFull> stub)
|
void init(FreeObject::QueuePtr<capptr::bounds::Alloc> stub)
|
||||||
{
|
{
|
||||||
FreeObject::atomic_store_null(stub, key_global);
|
FreeObject::atomic_store_null(stub, key_global);
|
||||||
front = stub;
|
front = stub;
|
||||||
@@ -58,9 +58,9 @@ namespace snmalloc
|
|||||||
invariant();
|
invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeObject::QueuePtr<capptr::bounds::AllocFull> destroy()
|
FreeObject::QueuePtr<capptr::bounds::Alloc> destroy()
|
||||||
{
|
{
|
||||||
FreeObject::QueuePtr<capptr::bounds::AllocFull> fnt = front;
|
FreeObject::QueuePtr<capptr::bounds::Alloc> fnt = front;
|
||||||
back.store(nullptr, std::memory_order_relaxed);
|
back.store(nullptr, std::memory_order_relaxed);
|
||||||
front = nullptr;
|
front = nullptr;
|
||||||
return fnt;
|
return fnt;
|
||||||
@@ -68,7 +68,7 @@ namespace snmalloc
|
|||||||
|
|
||||||
inline bool is_empty()
|
inline bool is_empty()
|
||||||
{
|
{
|
||||||
FreeObject::QueuePtr<capptr::bounds::AllocFull> bk =
|
FreeObject::QueuePtr<capptr::bounds::Alloc> bk =
|
||||||
back.load(std::memory_order_relaxed);
|
back.load(std::memory_order_relaxed);
|
||||||
|
|
||||||
return bk == front;
|
return bk == front;
|
||||||
@@ -79,22 +79,22 @@ namespace snmalloc
|
|||||||
* last should be linked together through their next pointers.
|
* last should be linked together through their next pointers.
|
||||||
*/
|
*/
|
||||||
void enqueue(
|
void enqueue(
|
||||||
FreeObject::QueuePtr<capptr::bounds::AllocFull> first,
|
FreeObject::QueuePtr<capptr::bounds::Alloc> first,
|
||||||
FreeObject::QueuePtr<capptr::bounds::AllocFull> last,
|
FreeObject::QueuePtr<capptr::bounds::Alloc> last,
|
||||||
const FreeListKey& key)
|
const FreeListKey& key)
|
||||||
{
|
{
|
||||||
invariant();
|
invariant();
|
||||||
FreeObject::atomic_store_null(last, key);
|
FreeObject::atomic_store_null(last, key);
|
||||||
|
|
||||||
// exchange needs to be a release, so nullptr in next is visible.
|
// exchange needs to be a release, so nullptr in next is visible.
|
||||||
FreeObject::QueuePtr<capptr::bounds::AllocFull> prev =
|
FreeObject::QueuePtr<capptr::bounds::Alloc> prev =
|
||||||
back.exchange(last, std::memory_order_release);
|
back.exchange(last, std::memory_order_release);
|
||||||
|
|
||||||
// XXX prev is not known to be domesticated
|
// XXX prev is not known to be domesticated
|
||||||
FreeObject::atomic_store_next(prev, first, key);
|
FreeObject::atomic_store_next(prev, first, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeObject::QueuePtr<capptr::bounds::AllocFull> peek()
|
FreeObject::QueuePtr<capptr::bounds::Alloc> peek()
|
||||||
{
|
{
|
||||||
return front;
|
return front;
|
||||||
}
|
}
|
||||||
@@ -103,16 +103,16 @@ namespace snmalloc
|
|||||||
* Returns the front message, or null if not possible to return a message.
|
* Returns the front message, or null if not possible to return a message.
|
||||||
*/
|
*/
|
||||||
std::pair<
|
std::pair<
|
||||||
FreeObject::HeadPtr<capptr::bounds::AllocFull, capptr::bounds::AllocFull>,
|
FreeObject::HeadPtr<capptr::bounds::Alloc, capptr::bounds::Alloc>,
|
||||||
bool>
|
bool>
|
||||||
dequeue(const FreeListKey& key)
|
dequeue(const FreeListKey& key)
|
||||||
{
|
{
|
||||||
auto domesticate = [](FreeObject::QueuePtr<capptr::bounds::AllocFull> p)
|
auto domesticate = [](FreeObject::QueuePtr<capptr::bounds::Alloc> p)
|
||||||
SNMALLOC_FAST_PATH_LAMBDA { return p; };
|
SNMALLOC_FAST_PATH_LAMBDA { return p; };
|
||||||
invariant();
|
invariant();
|
||||||
FreeObject::HeadPtr<capptr::bounds::AllocFull, capptr::bounds::AllocFull>
|
FreeObject::HeadPtr<capptr::bounds::Alloc, capptr::bounds::Alloc> first =
|
||||||
first = domesticate(front);
|
domesticate(front);
|
||||||
FreeObject::QueuePtr<capptr::bounds::AllocFull> next =
|
FreeObject::QueuePtr<capptr::bounds::Alloc> next =
|
||||||
first->atomic_read_next(key, domesticate);
|
first->atomic_read_next(key, domesticate);
|
||||||
|
|
||||||
if (next != nullptr)
|
if (next != nullptr)
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ namespace snmalloc
|
|||||||
std::array<
|
std::array<
|
||||||
FreeListBuilder<
|
FreeListBuilder<
|
||||||
false,
|
false,
|
||||||
capptr::bounds::AllocFull,
|
capptr::bounds::Alloc,
|
||||||
capptr::bounds::AllocFull,
|
capptr::bounds::Alloc,
|
||||||
false>,
|
false>,
|
||||||
REMOTE_SLOTS>
|
REMOTE_SLOTS>
|
||||||
list;
|
list;
|
||||||
@@ -73,12 +73,12 @@ namespace snmalloc
|
|||||||
template<size_t allocator_size>
|
template<size_t allocator_size>
|
||||||
SNMALLOC_FAST_PATH void dealloc(
|
SNMALLOC_FAST_PATH void dealloc(
|
||||||
RemoteAllocator::alloc_id_t target_id,
|
RemoteAllocator::alloc_id_t target_id,
|
||||||
capptr::AllocFull<void> p,
|
capptr::Alloc<void> p,
|
||||||
const FreeListKey& key)
|
const FreeListKey& key)
|
||||||
{
|
{
|
||||||
SNMALLOC_ASSERT(initialised);
|
SNMALLOC_ASSERT(initialised);
|
||||||
auto r =
|
auto r =
|
||||||
p.template as_reinterpret<FreeObject::T<capptr::bounds::AllocFull>>();
|
p.template as_reinterpret<FreeObject::T<capptr::bounds::Alloc>>();
|
||||||
|
|
||||||
list[get_slot<allocator_size>(target_id, 0)].add(r, key);
|
list[get_slot<allocator_size>(target_id, 0)].add(r, key);
|
||||||
}
|
}
|
||||||
@@ -118,8 +118,7 @@ namespace snmalloc
|
|||||||
// Entries could map back onto the "resend" list,
|
// Entries could map back onto the "resend" list,
|
||||||
// so take copy of the head, mark the last element,
|
// so take copy of the head, mark the last element,
|
||||||
// and clear the original list.
|
// and clear the original list.
|
||||||
FreeListIter<capptr::bounds::AllocFull, capptr::bounds::AllocFull>
|
FreeListIter<capptr::bounds::Alloc, capptr::bounds::Alloc> resend;
|
||||||
resend;
|
|
||||||
list[my_slot].close(resend, key);
|
list[my_slot].close(resend, key);
|
||||||
|
|
||||||
post_round++;
|
post_round++;
|
||||||
|
|||||||
Reference in New Issue
Block a user