Expose pool sort. (#565)

This commit is contained in:
Matthew Parkinson
2022-10-10 17:13:10 +01:00
committed by GitHub
parent a060462ff6
commit ddc5703cc8
2 changed files with 102 additions and 0 deletions

View File

@@ -190,5 +190,42 @@ namespace snmalloc
return p->list_next.unsafe_ptr();
}
/**
* Put the stack in a consistent order. This is helpful for systematic
* testing based systems. It is not thread safe, and the caller should
* ensure no other thread can be performing a `sort` concurrently with this
* call.
*/
static void sort()
{
// Marker is used to signify free elements.
auto marker = reinterpret_cast<T*>(1);
// Extract all the elements and mark them as free.
T* curr = extract();
T* prev = nullptr;
while (curr != nullptr)
{
prev = curr;
curr = extract(curr);
// Assignment must occur after extract, otherwise extract would read the
// marker
prev->next = marker;
}
// Build a list of the free elements in the correct order.
// This is the opposite order to the list of all elements
// so that iterate works correctly.
curr = iterate();
while (curr != nullptr)
{
if (curr->next == marker)
{
get_state().stack.push(curr);
}
curr = iterate(curr);
}
}
};
} // namespace snmalloc

View File

@@ -43,6 +43,17 @@ struct PoolLargeEntry : Pooled<PoolLargeEntry>
using PoolLarge = Pool<PoolLargeEntry, Alloc::Config>;
template<bool order>
struct PoolSortEntry : Pooled<PoolSortEntry<order>>
{
int field;
PoolSortEntry(int f) : field(f){};
};
template<bool order>
using PoolSort = Pool<PoolSortEntry<order>, Alloc::Config>;
void test_alloc()
{
auto ptr = PoolA::acquire();
@@ -147,6 +158,56 @@ void test_large()
fflush(stdout);
}
/**
* This test confirms that the pool is sorted consistently with
* respect to the iterator after a call to sort.
*/
template<bool order>
void test_sort()
{
auto position = [](PoolSortEntry<order>* ptr) {
size_t i = 0;
auto curr = PoolSort<order>::iterate();
while (ptr != curr)
{
curr = PoolSort<order>::iterate(curr);
++i;
}
return i;
};
// This test checks that `sort` puts the elements in the right order,
// so it is the same as if they had been allocated in that order.
auto a1 = PoolSort<order>::acquire(1);
auto a2 = PoolSort<order>::acquire(1);
auto position1 = position(a1);
auto position2 = position(a2);
// Release in either order.
if (order)
{
PoolSort<order>::release(a1);
PoolSort<order>::release(a2);
}
else
{
PoolSort<order>::release(a2);
PoolSort<order>::release(a1);
}
PoolSort<order>::sort();
auto b1 = PoolSort<order>::acquire(1);
auto b2 = PoolSort<order>::acquire(1);
SNMALLOC_CHECK(position1 == position(b1));
SNMALLOC_CHECK(position2 == position(b2));
PoolSort<order>::release(b1);
PoolSort<order>::release(b2);
}
int main(int argc, char** argv)
{
setup();
@@ -172,5 +233,9 @@ int main(int argc, char** argv)
std::cout << "test_iterator passed" << std::endl;
test_large();
std::cout << "test_large passed" << std::endl;
test_sort<false>();
std::cout << "test_sort<false> passed" << std::endl;
test_sort<true>();
std::cout << "test_sort<true> passed" << std::endl;
return 0;
}