1/* @title: RCU */
2#pragma once
3#include <compiler.h>
4#include <stdatomic.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include <structures/list.h>
8#include <sync/semaphore.h>
9#include <sync/spinlock.h>
10
11#define RCU_BUCKETS 2
12
13struct rcu_cpu {
14 _Atomic uint32_t nesting; /* lock depth */
15 _Atomic uint64_t read_gen; /* generation at outermost lock */
16 _Atomic uint64_t qs_gen; /* last confirmed quiescent gen */
17
18 /* TODO: #define CACHE LINE SIZE somewhere */
19 uint8_t _pad[64 - (sizeof(uint32_t) + 2 * sizeof(uint64_t)) % 64];
20} __cache_aligned;
21
22struct rcu_cb;
23typedef void (*rcu_fn)(struct rcu_cb *, void *);
24
25struct rcu_cb {
26 struct list_head list;
27 rcu_fn fn;
28 void *arg;
29 size_t gen_when_called;
30 size_t enqueued_waiting_on_gen;
31 size_t target_gen;
32};
33#define rcu_cb_from_list_node(ln) (container_of(ln, struct rcu_cb, list))
34
35struct rcu_bucket {
36 struct spinlock lock;
37 struct list_head list;
38};
39
40struct rcu_buckets {
41 struct semaphore sem;
42 struct rcu_bucket buckets[RCU_BUCKETS];
43};
44
45struct rcu_gp {
46 _Atomic uint64_t current_gen;
47 struct rcu_cpu *cpus;
48};
49
50void rcu_synchronize(void);
51void rcu_defer(struct rcu_cb *cb, rcu_fn fn, void *arg);
52void rcu_maintenance_tick(void);
53void rcu_read_lock(void);
54void rcu_read_unlock(void);
55void rcu_init(void);
56void rcu_worker_notify(void);
57
58#define rcu_dereference(p) atomic_load_explicit(&(p), memory_order_acquire)
59
60#define rcu_assign_pointer(p, v) \
61 atomic_store_explicit(&(p), (v), memory_order_release)
62