8#include "pedigree/kernel/Atomic.h"
9#include "pedigree/kernel/Log.h"
10#include "pedigree/kernel/core/SlamAllocator.h"
11#include "pedigree/kernel/process/Scheduler.h"
12#include "pedigree/kernel/process/Thread.h"
13#include "pedigree/kernel/processor/Processor.h"
16constexpr size_t ObjectSize = 128;
17constexpr size_t ObjectCount = SLAB_MINIMUM_SIZE / ObjectSize;
19void prepareAllocation(
SlamCache& cache, uintptr_t
object) {
21 header->cache = &cache;
23 header->magic = VIGILANT_MAGIC;
26 footer->magic = VIGILANT_MAGIC;
30struct RemoteFreeContext {
31 RemoteFreeContext(
SlamCache& cache, uintptr_t* objects,
size_t count,
size_t allocatingProcessor)
35 allocatingProcessor(allocatingProcessor),
36 processor(static_cast<size_t>(-1)) {}
41 size_t allocatingProcessor;
45int freeRemotely(
void* parameter) {
46 RemoteFreeContext* context =
reinterpret_cast<RemoteFreeContext*
>(parameter);
48 if (processor == context->allocatingProcessor ||
49 !context->processor.compareAndSwap(
static_cast<size_t>(-1), processor)) {
52 for (
size_t i = 0; i < context->count; ++i) {
53 context->cache.free(context->objects[i]);
58bool runRemoteFree(RemoteFreeContext& context) {
62 for (; started < processorCount; ++started) {
64 nullptr,
false,
false,
true);
65 workers[started]->setName(
"QEMU SLAM remote freer");
66 if (!workers[started]->start()) {
72 for (
size_t i = 0; i < started; ++i) {
75 return started == processorCount && joined &&
76 context.processor.value() !=
static_cast<size_t>(-1);
80bool runSlamAllocatorConcurrencyRegression() {
81 NOTICE(
"QEMU-CONCURRENCY-TEST: BEGIN slam-cross-cpu-recovery-smp");
84 if (processorCount < 2 || processorCount > 64) {
85 ERROR(
"QEMU SLAM regression requires between two and 64 processors");
93 uintptr_t objects[ObjectCount] = {};
95 const size_t objectCount = cache.slabObjectCount();
96 if (!objectCount || objectCount > ObjectCount) {
99 for (
size_t i = 0; i < objectCount; ++i) {
101 prepareAllocation(cache, objects[i]);
105 RemoteFreeContext firstFree(cache, objects, objectCount, allocatingProcessor);
106 if (!runRemoteFree(firstFree) || firstFree.processor == allocatingProcessor) {
108 "QEMU-CONCURRENCY-TEST: FAIL slam-cross-cpu-recovery-smp: "
109 "free worker did not complete on a remote CPU");
113 uintptr_t reused = cache.
allocate();
114 if ((reused & ~(SLAB_MINIMUM_SIZE - 1)) != (objects[0] & ~(SLAB_MINIMUM_SIZE - 1))) {
116 "QEMU-CONCURRENCY-TEST: FAIL slam-cross-cpu-recovery-smp: "
117 "remote free list was stranded");
120 prepareAllocation(cache, reused);
122 RemoteFreeContext finalFree(cache, &reused, 1, allocatingProcessor);
123 if (!runRemoteFree(finalFree) || cache.
recovery(1) != 1) {
125 "QEMU-CONCURRENCY-TEST: FAIL slam-cross-cpu-recovery-smp: "
126 "cross-CPU sub-page slab was not reclaimed");
130 NOTICE(
"QEMU-CONCURRENCY-TEST: slam cpus=" <<
Dec << allocatingProcessor <<
"/"
131 <<
static_cast<size_t>(firstFree.processor) <<
"/"
132 <<
static_cast<size_t>(finalFree.processor));
133 NOTICE(
"QEMU-CONCURRENCY-TEST: PASS slam-cross-cpu-recovery-smp");
static Scheduler & instance()
void initialise(SlamAllocator *parent, size_t objectSize)
size_t recovery(size_t maxSlabs)