2#include "pedigree/kernel/Atomic.h"
3#include "pedigree/kernel/Log.h"
4#include "pedigree/kernel/process/Rcu.h"
5#include "pedigree/kernel/process/Scheduler.h"
6#include "pedigree/kernel/process/Thread.h"
7#include "pedigree/kernel/processor/Processor.h"
8#include "pedigree/kernel/time/Time.h"
16void reclaim(
void* pointer) {
17 auto* value =
static_cast<Value*
>(pointer);
18 *value->reclaimed += 1;
24 Atomic<size_t> reclaimed{0}, ready{0}, release{0}, failed{0}, draining{0}, drained{0};
30int readRemotely(
void* parameter) {
31 auto& context = *
static_cast<Context*
>(parameter);
33 if (cpu == context.writerCpu || !context.readerCpu.compareAndSwap(~
size_t{0}, cpu)) {
38 const Value* value = context.publication.load(outer);
46 const auto deadline = Time::getTicks() + 5 * Time::Multiplier::Second;
47 while (!context.release.value() && Time::getTicks() < deadline) {
50 if (!context.release.value() || !value || value->value != 17 || context.reclaimed.value()) {
60int drainRemotely(
void* parameter) {
61 auto& context = *
static_cast<Context*
>(parameter);
63 context.retired.drain();
69 const auto deadline = Time::getTicks() + 5 * Time::Multiplier::Second;
70 while (!flag.value() && Time::getTicks() < deadline) {
73 return flag.value() != 0;
77bool runRcuConcurrencyRegression() {
78 NOTICE(
"QEMU-CONCURRENCY-TEST: BEGIN rcu-publication-reclamation-smp");
80 if (cpus < 4 || cpus > 64) {
84 context.publication.exchange(
new Value{17, &context.reclaimed});
86 for (
size_t i = 0; i < cpus; ++i) {
88 nullptr,
false,
false,
true);
89 if (!readers[i]->start()) {
90 FATAL(
"RCU smoke reader could not start");
93 if (!waitFor(context.ready)) {
94 FATAL(
"RCU smoke reader did not enter on another CPU");
96 Value* previous = context.publication.exchange(
new Value{29, &context.reclaimed});
97 context.retired.retire(previous, reclaim);
99 placement.allowed.set(context.writerCpu);
101 nullptr,
false,
false,
true, &placement);
102 if (!drainer->
start() || !waitFor(context.draining)) {
103 FATAL(
"RCU smoke reclaimer could not start");
105 for (
size_t i = 0; i < 64; ++i) {
108 if (context.drained.value() || context.reclaimed.value()) {
113 for (
size_t i = 0; i < cpus; ++i) {
116 if (!joined || context.failed.value() || context.reclaimed.value() != 1) {
120 previous = context.publication.exchange(
nullptr);
121 context.retired.retire(previous, reclaim);
122 for (
size_t i = 1; i <= RcuRetireQueue::Capacity; ++i) {
123 context.retired.retire(
new Value{i, &context.reclaimed}, reclaim);
125 if (context.reclaimed.value() != 1 + RcuRetireQueue::Capacity) {
128 context.retired.drain();
129 if (context.reclaimed.value() != 2 + RcuRetireQueue::Capacity) {
132 NOTICE(
"QEMU-CONCURRENCY-TEST: RCU reader CPU=" <<
Dec << context.readerCpu.value()
133 <<
", writer CPU=" << context.writerCpu);
134 NOTICE(
"QEMU-CONCURRENCY-TEST: PASS rcu-publication-reclamation-smp");
static bool getInterrupts()
static Scheduler & instance()