PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
rcu.h
Go to the documentation of this file.
1#pragma once
2
3#include <kernel/cpu/cli.h>
5
7#include <stdatomic.h>
8#include <stdint.h>
9#include <sys/fs.h>
10#include <sys/list.h>
11#include <sys/proc.h>
12
13typedef struct rcu_entry rcu_entry_t;
14
15/**
16 * @brief Read-Copy-Update (RCU) primitive.
17 * @defgroup kernel_sync_rcu Read-Copy-Update (RCU)
18 * @ingroup kernel_sync
19 *
20 * RCU is a synchronization mechanism that allows readers to access shared data structures concurrently with writers,
21 * without using locks.
22 *
23 * ## Implementation
24 *
25 * RCU works by delaying the freeing of a resource until its known to be impossible for any CPU to be using said
26 * resource.
27 *
28 * This is implemented by allowing the resource to persist for a grace period, which is defined as the time taken for
29 * all CPUs to pass through a quiescent state. A quiescent state is any point at which the CPU is known to not be
30 * accessing RCU protected data.
31 *
32 * In our case, it is illegal for a context switch to occur while accessing RCU protected data, as preemption is
33 * disabled using `rcu_read_lock()`. Therefor, we know that once all CPUs, which were not idle, have performed a context
34 * switch, they must have passed through a quiescent state and it is thus safe to free any pending resources.
35 *
36 * ## Using RCU
37 *
38 * Using RCU is fairly straightforward, any data structure that is to be protected by RCU must include a `rcu_entry_t`
39 * member, when the structure is to be freed after use `rcu_call()` should be called with the address of the
40 * `rcu_entry_t` member and a callback function that will free the structure.
41 *
42 * To access RCU protected data, a read-side critical section must be created using `rcu_read_lock()` and
43 * `rcu_read_unlock()`, or the `RCU_READ_SCOPE()` macro.
44 *
45 * @see [Wikipedia](https://en.wikipedia.org/wiki/Read-copy-update) for more information about RCU.
46 * @see [kernel.org](https://www.kernel.org/doc/Documentation/RCU/whatisRCU.txt) for a explanation of RCU in the Linux
47 * kernel.
48 *
49 * @{
50 */
51
52/**
53 * @brief RCU callback function type.
54 *
55 * @param rcu The RCU entry being processed.
56 */
57typedef void (*rcu_callback_t)(void* arg);
58
59/**
60 * @brief Intrusive RCU head structure.
61 *
62 * Used to queue objects for freeing.
63 */
64typedef struct rcu_entry
65{
68 void* arg;
70
71/**
72 * @brief RCU read-side critical section begin.
73 *
74 * Should be called before accessing RCU protected data.
75 */
76static inline void rcu_read_lock(void)
77{
79}
80
81/**
82 * @brief RCU read-side critical section end.
83 *
84 * Should be called after accessing RCU protected data.
85 */
86static inline void rcu_read_unlock(void)
87{
89}
90
91/**
92 * @brief RCU read-side critical section for the current scope.
93 */
94#define RCU_READ_SCOPE() \
95 rcu_read_lock(); \
96 __attribute__((cleanup(rcu_read_unlock_cleanup))) int CONCAT(r, __COUNTER__) = 1;
97
98/**
99 * @brief Wait for all pre-existing RCU read-side critical sections to complete.
100 *
101 * This function blocks until all RCU read-side critical sections that were active
102 * at the time of the call have completed.
103 */
104void rcu_synchronize(void);
105
106/**
107 * @brief Add a callback to be executed after a grace period.
108 *
109 * @param entry The RCU entry structure embedded in the object to be freed.
110 * @param func The callback function to execute.
111 */
112void rcu_call(rcu_entry_t* entry, rcu_callback_t func, void* arg);
113
114/**
115 * @brief Called during a context switch to report a quiescent state.
116 */
117void rcu_report_quiescent(void);
118
119/**
120 * @brief Helper callback to free a pointer.
121 *
122 * Can be used as a generic callback to free memory allocated with `malloc()`.
123 *
124 * @param arg The pointer to free.
125 */
126void rcu_call_free(void* arg);
127
128/**
129 * @brief Helper callback to free a cache object.
130 *
131 * Can be used as a generic callback to free memory allocated from a cache.
132 *
133 * @param arg The pointer to free.
134 */
135void rcu_call_cache_free(void* arg);
136
137static inline void rcu_read_unlock_cleanup(int* _)
138{
140}
141
142/** @} */
void sched_disable(void)
Disables preemption on the current CPU.
Definition sched.c:638
void sched_enable(void)
Enables preemption on the current CPU.
Definition sched.c:646
static void rcu_read_unlock(void)
RCU read-side critical section end.
Definition rcu.h:86
void rcu_report_quiescent(void)
Called during a context switch to report a quiescent state.
Definition rcu.c:173
void rcu_call_free(void *arg)
Helper callback to free a pointer.
Definition rcu.c:188
static void rcu_read_unlock_cleanup(int *_)
Definition rcu.h:137
void rcu_call_cache_free(void *arg)
Helper callback to free a cache object.
Definition rcu.c:193
void(* rcu_callback_t)(void *arg)
RCU callback function type.
Definition rcu.h:57
void rcu_synchronize(void)
Wait for all pre-existing RCU read-side critical sections to complete.
Definition rcu.c:56
static void rcu_read_lock(void)
RCU read-side critical section begin.
Definition rcu.h:76
void rcu_call(rcu_entry_t *entry, rcu_callback_t func, void *arg)
Add a callback to be executed after a grace period.
Definition rcu.c:72
A entry in a doubly linked list.
Definition list.h:37
Intrusive RCU head structure.
Definition rcu.h:65
void * arg
Definition rcu.h:68
rcu_callback_t func
Definition rcu.h:67
list_entry_t entry
Definition rcu.h:66