PatchworkOS  69292a3
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/io.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 kernel.
47 *
48 * @{
49 */
50
51/**
52 * @brief RCU callback function type.
53 *
54 * @param rcu The RCU entry being processed.
55 */
56typedef void (*rcu_callback_t)(void* arg);
57
58/**
59 * @brief Intrusive RCU head structure.
60 *
61 * Used to queue objects for freeing.
62 */
63typedef struct rcu_entry
64{
67 void* arg;
69
70/**
71 * @brief RCU read-side critical section begin.
72 *
73 * Should be called before accessing RCU protected data.
74 */
75static inline void rcu_read_lock(void)
76{
78}
79
80/**
81 * @brief RCU read-side critical section end.
82 *
83 * Should be called after accessing RCU protected data.
84 */
85static inline void rcu_read_unlock(void)
86{
88}
89
90/**
91 * @brief RCU read-side critical section for the current scope.
92 */
93#define RCU_READ_SCOPE() \
94 rcu_read_lock(); \
95 __attribute__((cleanup(rcu_read_unlock_cleanup))) int CONCAT(r, __COUNTER__) = 1;
96
97/**
98 * @brief Wait for all pre-existing RCU read-side critical sections to complete.
99 *
100 * This function blocks until all RCU read-side critical sections that were active
101 * at the time of the call have completed.
102 */
103void rcu_synchronize(void);
104
105/**
106 * @brief Add a callback to be executed after a grace period.
107 *
108 * @param entry The RCU entry structure embedded in the object to be freed.
109 * @param func The callback function to execute.
110 */
111void rcu_call(rcu_entry_t* entry, rcu_callback_t func, void* arg);
112
113/**
114 * @brief Called during a context switch to report a quiescent state.
115 */
116void rcu_report_quiescent(void);
117
118/**
119 * @brief Helper callback to free a pointer.
120 *
121 * Can be used as a generic callback to free memory allocated with `malloc()`.
122 *
123 * @param arg The pointer to free.
124 */
125void rcu_call_free(void* arg);
126
127/**
128 * @brief Helper callback to free a cache object.
129 *
130 * Can be used as a generic callback to free memory allocated from a cache.
131 *
132 * @param arg The pointer to free.
133 */
134void rcu_call_cache_free(void* arg);
135
136static inline void rcu_read_unlock_cleanup(int* _)
137{
139}
140
141/** @} */
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:85
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:136
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:56
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:75
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:64
void * arg
Definition rcu.h:67
rcu_callback_t func
Definition rcu.h:66
list_entry_t entry
Definition rcu.h:65