1/* @title: RCU */
2#pragma once
3#include <compiler.h>
4#include <stdatomic.h>
5#include <stdbool.h>
6#include <stddef.h>
7#include <stdint.h>
8#include <structures/list.h>
9
10struct thread;
11
12/* Forward declaration so we can put this pointer in threads */
13struct rcu_node;
14
15struct rcu_cb;
16typedef void (*rcu_fn)(struct rcu_cb *, void *);
17
18struct rcu_cb {
19 struct list_head list;
20 rcu_fn fn;
21 void *arg;
22
23 size_t gen_when_called; /* Diagnostics */
24 size_t enqueued_waiting_on_gen;
25 size_t target_gen;
26};
27#define rcu_cb_from_list_node(ln) (container_of(ln, struct rcu_cb, list))
28
29void rcu_init(void);
30
31void rcu_read_lock(void);
32void rcu_read_unlock(void);
33
34void rcu_synchronize(void);
35void rcu_defer(struct rcu_cb *cb, rcu_fn fn, void *arg);
36
37/* TODO: next_is_idle is a little funny... perhaps it's better to explicitly
38 * state *prev, *next here and just check the idle state inside */
39void rcu_note_context_switch(struct thread *outgoing, bool next_is_idle);
40void rcu_note_irq_exit(void);
41
42#define rcu_dereference(p) atomic_load_explicit(&(p), memory_order_acquire)
43
44#define rcu_assign_pointer(p, v) \
45 atomic_store_explicit(&(p), (v), memory_order_release)
46