99 lines
2.9 KiB
C++
99 lines
2.9 KiB
C++
/*
|
|
* Read-Copy Update (RCU)
|
|
*
|
|
* Copyright (C) 2009-2011 Udo Steinberg <udo@hypervisor.org>
|
|
* Economic rights: Technische Universitaet Dresden (Germany)
|
|
*
|
|
* Copyright (C) 2012-2013 Udo Steinberg, Intel Corporation.
|
|
* Copyright (C) 2019-2025 Udo Steinberg, BlueRock Security, Inc.
|
|
*
|
|
* This file is part of the NOVA microhypervisor.
|
|
*
|
|
* NOVA is free software: you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* NOVA is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License version 2 for more details.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "atomic.hpp"
|
|
#include "macros.hpp"
|
|
#include "types.hpp"
|
|
|
|
class Rcu_elem
|
|
{
|
|
public:
|
|
Rcu_elem *next;
|
|
void (*func)(Rcu_elem *);
|
|
|
|
Rcu_elem (void (*f)(Rcu_elem *)) : next { nullptr }, func { f } {}
|
|
};
|
|
|
|
class Rcu
|
|
{
|
|
private:
|
|
class List
|
|
{
|
|
public:
|
|
Rcu_elem * head;
|
|
Rcu_elem ** tail;
|
|
|
|
List() { clear(); }
|
|
|
|
void clear() { head = nullptr; tail = &head; }
|
|
|
|
void append (List *l)
|
|
{
|
|
*tail = l->head;
|
|
tail = l->tail;
|
|
l->clear();
|
|
}
|
|
|
|
void enqueue (Rcu_elem *e)
|
|
{
|
|
e->next = nullptr;
|
|
*tail = e;
|
|
tail = &e->next;
|
|
}
|
|
};
|
|
|
|
using Epoch = unsigned long;
|
|
|
|
enum State
|
|
{
|
|
COMPLETED = BIT (0), // Completed epoch E
|
|
REQUESTED = BIT (1), // Requested epoch E+1
|
|
FULL = REQUESTED | COMPLETED,
|
|
};
|
|
|
|
// Epoch and state tracking
|
|
static inline constinit Atomic<Epoch, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST> epoch { State::COMPLETED };
|
|
|
|
// Number of CPUs that still need to pass through a quiescent state in epoch E
|
|
static inline constinit Atomic<cpu_t, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST> count { 0 };
|
|
|
|
static List next CPULOCAL; // Callbacks handled in a future epoch
|
|
static List curr CPULOCAL; // Callbacks handled in epoch_c
|
|
static List done CPULOCAL; // Callbacks completed in earlier epochs
|
|
|
|
static Epoch epoch_l CPULOCAL; // Epoch for which quiescent state will be reported
|
|
static Epoch epoch_c CPULOCAL; // Epoch for which current callbacks are handled
|
|
|
|
static void set_state (State);
|
|
|
|
static bool complete (Epoch e, Epoch c) { return static_cast<signed long>((e & ~State::REQUESTED) - (c << 2)) > 0; }
|
|
|
|
static void handle_callbacks();
|
|
|
|
public:
|
|
static void quiet();
|
|
static void check();
|
|
|
|
static void submit (Rcu_elem *e) { next.enqueue (e); }
|
|
};
|