PatchworkOS  69292a3
A non-POSIX operating system.
Loading...
Searching...
No Matches
rcu.c
Go to the documentation of this file.
1#include <kernel/cpu/cpu.h>
2#include <kernel/cpu/ipi.h>
3#include <kernel/log/log.h>
4#include <kernel/mem/cache.h>
5#include <kernel/sync/lock.h>
6#include <kernel/sync/rcu.h>
7
8#include <stdlib.h>
9#include <sys/bitmap.h>
10
12static uint64_t grace = 0;
13static bool active = false;
15
16typedef struct rcu
17{
18 uint64_t grace; ///< The last grace period observed by this CPU.
19 list_t* batch; ///< Callbacks queued during the current grace period.
20 list_t* waiting; ///< Callbacks waiting for the current grace period to end.
21 list_t* ready; ///< Callbacks whose grace period has ended.
22 list_t lists[3]; //< Buffer storing three lists such that we can rotate them.
23} rcu_t;
24
25PERCPU_DEFINE_CTOR(static rcu_t, pcpu_rcu)
26{
27 rcu_t* rcu = SELF_PTR(pcpu_rcu);
28
29 rcu->grace = 0;
30 rcu->batch = &rcu->lists[0];
31 rcu->waiting = &rcu->lists[1];
32 rcu->ready = &rcu->lists[2];
33 for (size_t i = 0; i < ARRAY_SIZE(rcu->lists); i++)
34 {
35 list_init(&rcu->lists[i]);
36 }
37}
38
46
47static void rcu_synchronize_callback(void* arg)
48{
50 lock_acquire(&sync->lock);
51 sync->done = true;
52 wait_unblock(&sync->wait, WAIT_ALL, EOK);
53 lock_release(&sync->lock);
54}
55
57{
59 wait_queue_init(&sync.wait);
60 lock_init(&sync.lock);
61 sync.done = false;
62
64
65 lock_acquire(&sync.lock);
66 WAIT_BLOCK_LOCK(&sync.wait, &sync.lock, sync.done);
67 lock_release(&sync.lock);
68
70}
71
72void rcu_call(rcu_entry_t* entry, rcu_callback_t func, void* arg)
73{
74 if (entry == NULL || func == NULL)
75 {
76 return;
77 }
78
79 CLI_SCOPE();
80
81 list_entry_init(&entry->entry);
82 entry->func = func;
83 entry->arg = arg;
84
85 list_push_back(pcpu_rcu->batch, &entry->entry);
86}
87
88static bool rcu_check_quiescent(void)
89{
91 if (active && bitmap_is_set(&ack, SELF->id))
92 {
93 bitmap_clear(&ack, SELF->id);
94
95 if (bitmap_is_empty(&ack))
96 {
97 active = false;
98 }
99 }
100
101 bool wake = false;
102 if (!list_is_empty(pcpu_rcu->waiting))
103 {
104 if (grace > pcpu_rcu->grace || (grace == pcpu_rcu->grace && !active))
105 {
106 wake = true;
107 }
108 }
110 return wake;
111}
112
113static void rcu_advance(bool wake)
114{
115 if (wake)
116 {
117 list_t* temp = pcpu_rcu->ready;
118 pcpu_rcu->ready = pcpu_rcu->waiting;
119 pcpu_rcu->waiting = temp;
120 }
121
122 if (list_is_empty(pcpu_rcu->waiting) && !list_is_empty(pcpu_rcu->batch))
123 {
124 list_t* temp = pcpu_rcu->waiting;
125 pcpu_rcu->waiting = pcpu_rcu->batch;
126 pcpu_rcu->batch = temp;
127
129 pcpu_rcu->grace = grace + 1;
131 pcpu_rcu->grace = active ? grace : grace + 1;
132 }
133}
134
135static void rcu_start_grace(void)
136{
137 if (list_is_empty(pcpu_rcu->waiting))
138 {
139 return;
140 }
141
143 if (active)
144 {
145 return;
146 }
147
148 active = true;
149 grace++;
150
151 bitmap_set_range(&ack, 0, cpu_amount());
152 cpu_t* cpu;
153 CPU_FOR_EACH(cpu)
154 {
155 if (!sched_is_idle(cpu))
156 {
157 continue;
158 }
159
160 bitmap_clear(&ack, cpu->id);
161 }
162}
163
164static void rcu_invoke_callbacks(void)
165{
166 while (!list_is_empty(pcpu_rcu->ready))
167 {
168 rcu_entry_t* entry = CONTAINER_OF(list_pop_front(pcpu_rcu->ready), rcu_entry_t, entry);
169 entry->func(entry->arg);
170 }
171}
172
174{
176
177 bool wake = rcu_check_quiescent();
178
180
181 rcu_advance(wake);
182
184
186}
187
188void rcu_call_free(void* arg)
189{
190 free(arg);
191}
192
193void rcu_call_cache_free(void* arg)
194{
195 cache_free(arg);
196}
#define assert(expression)
Definition assert.h:29
#define CLI_SCOPE()
Macro to increment CLI depth for the duration of the current scope.
Definition cli.h:56
#define SELF_PTR(ptr)
Macro to get a pointer to a percpu variable on the current CPU.
Definition percpu.h:93
#define SELF
Macro to access data in the current cpu.
Definition percpu.h:85
#define PERCPU_DEFINE_CTOR(type, name)
Macro to define a percpu variable with a constructor.
Definition percpu.h:130
#define CPU_MAX
Maximum number of CPUs supported.
Definition cpu.h:50
static uint16_t cpu_amount(void)
Gets the number of identified CPUs.
Definition cpu.h:168
#define CPU_FOR_EACH(cpu)
Macro to iterate over all CPUs.
Definition cpu.h:214
void cache_free(void *obj)
Free an object back to its cache.
Definition cache.c:205
uint64_t wait_unblock(wait_queue_t *queue, uint64_t amount, errno_t err)
Unblock threads waiting on a wait queue.
Definition wait.c:307
void wait_queue_deinit(wait_queue_t *queue)
Deinitialize wait queue.
Definition wait.c:57
#define WAIT_ALL
Used to indicate that the wait should unblock all waiting threads.
Definition wait.h:43
void wait_queue_init(wait_queue_t *queue)
Initialize wait queue.
Definition wait.c:51
#define WAIT_BLOCK_LOCK(queue, lock, condition)
Blocks until the condition is true, condition will be tested on every wakeup. Will release the lock b...
Definition wait.h:109
bool sched_is_idle(cpu_t *cpu)
Checks if the CPU is currently idle.
Definition sched.c:618
static void lock_init(lock_t *lock)
Initializes a lock.
Definition lock.h:79
#define LOCK_CREATE()
Create a lock initializer.
Definition lock.h:69
#define LOCK_SCOPE(lock)
Acquires a lock for the reminder of the current scope.
Definition lock.h:58
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:175
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:96
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
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
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
#define EOK
No error.
Definition errno.h:32
#define BITMAP_CREATE_ZERO(name, bits)
Define and create a zero-initialized bitmap and its buffer.
Definition bitmap.h:83
static bool bitmap_is_empty(bitmap_t *map)
Check if the bitmap is empty (all bits clear).
Definition bitmap.h:131
static void bitmap_clear(bitmap_t *map, uint64_t index)
Clear a bit in the bitmap.
Definition bitmap.h:234
static bool bitmap_is_set(bitmap_t *map, uint64_t idx)
Check if a bit is set in the bitmap.
Definition bitmap.h:162
static void bitmap_set_range(bitmap_t *map, uint64_t low, uint64_t high)
Set a range of bits in the bitmap.
Definition bitmap.h:199
#define ARRAY_SIZE(x)
Get the number of elements in a static array.
Definition defs.h:115
static void list_push_back(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:321
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:210
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:173
static list_entry_t * list_pop_front(list_t *list)
Pops the first entry from the list.
Definition list.h:365
static void list_init(list_t *list)
Initializes a list.
Definition list.h:185
#define NULL
Pointer error value.
Definition NULL.h:25
#define CONTAINER_OF(ptr, type, member)
Container of macro.
static bool active
Definition rcu.c:13
static bool rcu_check_quiescent(void)
Definition rcu.c:88
static void rcu_advance(bool wake)
Definition rcu.c:113
static void rcu_invoke_callbacks(void)
Definition rcu.c:164
static lock_t lock
Definition rcu.c:14
static void rcu_synchronize_callback(void *arg)
Definition rcu.c:47
static uint64_t grace
Definition rcu.c:12
static void rcu_start_grace(void)
Definition rcu.c:135
#define RFLAGS_INTERRUPT_ENABLE
Definition regs.h:34
static uint64_t rflags_read(void)
Definition regs.h:80
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC void free(void *ptr)
Definition free.c:11
CPU structure.
Definition cpu.h:84
cpu_id_t id
Definition cpu.h:86
A doubly linked list.
Definition list.h:46
A simple ticket lock implementation.
Definition lock.h:44
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
rcu_entry_t rcu
Definition rcu.c:41
lock_t lock
Definition rcu.c:43
wait_queue_t wait
Definition rcu.c:42
Definition rcu.c:17
list_t * waiting
Callbacks waiting for the current grace period to end.
Definition rcu.c:20
list_t * batch
Callbacks queued during the current grace period.
Definition rcu.c:19
list_t * ready
Callbacks whose grace period has ended.
Definition rcu.c:21
list_t lists[3]
Definition rcu.c:22
uint64_t grace
The last grace period observed by this CPU.
Definition rcu.c:18
The primitive that threads block on.
Definition wait.h:185