PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
list.h
Go to the documentation of this file.
1#ifndef _SYS_LIST_H
2#define _SYS_LIST_H 1
3
5#include "_libstd/NULL.h"
6
7#include <assert.h>
8#include <stdatomic.h>
9#include <stdbool.h>
10#include <stdint.h>
11
12/**
13 * @brief Doubly linked list header.
14 * @ingroup libstd
15 * @defgroup libstd_sys_list Doubly linked list
16 *
17 * The `sys/list.h` header implements a intrusive doubly linked list.
18 *
19 * Given a entry within a structure, the `CONTAINER_OF()` macro can be used to get a pointer to the structure from the
20 * list entry pointer.
21 *
22 * @warning If a list is protected with RCU, the `list_*_rcu()` functions must be used.
23 *
24 * @{
25 */
26
27typedef struct list list_t;
28
29/**
30 * @brief A entry in a doubly linked list.
31 * @struct list_entry_t
32 *
33 * This structure should be placed within another structure so that the `CONTAINER_OF()` macro can then be used to
34 * access the other structure.
35 */
36typedef struct list_entry
37{
38 struct list_entry* prev; ///< The previous entry in the list
39 struct list_entry* next; ///< The next entry in the list
41
42/**
43 * @brief A doubly linked list.
44 */
45typedef struct list
46{
47 list_entry_t head; ///< The head of the list, where head::prev is the last entry of the list and head::next is the
48 /// first entry of the list.
49} list_t;
50
51/**
52 * @brief Iterates over a list.
53 *
54 * @param elem The loop variable, a pointer to the structure containing the list entry.
55 * @param list A pointer to the `list_t` structure to iterate over.
56 * @param member The name of the `list_entry_t` member within the structure `elem`.
57 */
58#define LIST_FOR_EACH(elem, list, member) \
59 for ((elem) = CONTAINER_OF((list)->head.next, typeof(*elem), member); &(elem)->member != &((list)->head); \
60 (elem) = CONTAINER_OF((elem)->member.next, typeof(*elem), member))
61
62/**
63 * @brief Safely iterates over a list, allowing for element removal during iteration.
64 *
65 * The `LIST_FOR_EACH_SAFE()` macro is similar to `LIST_FOR_EACH()` but uses a temporary variable to store the next
66 * element, making it safe to remove the current element during iteration.
67 *
68 * @param elem The loop variable, a pointer to the structure containing the list entry.
69 * @param temp A temporary loop variable, a pointer to the structure containing the next list entry.
70 * @param list A pointer to the `list_t` structure to iterate over.
71 * @param member The name of the `list_entry_t` member within the structure `elem`.
72 */
73#define LIST_FOR_EACH_SAFE(elem, temp, list, member) \
74 for ((elem) = CONTAINER_OF((list)->head.next, typeof(*elem), member), \
75 (temp) = CONTAINER_OF((elem)->member.next, typeof(*elem), member); \
76 &(elem)->member != &((list)->head); \
77 (elem) = (temp), (temp) = CONTAINER_OF((elem)->member.next, typeof(*elem), member))
78
79/**
80 * @brief Iterates over a list in reverse.
81 *
82 * @param elem The loop variable, a pointer to the structure containing the list entry.
83 * @param list A pointer to the `list_t` structure to iterate over.
84 * @param member The name of the `list_entry_t` member within the structure `elem`.
85 */
86#define LIST_FOR_EACH_REVERSE(elem, list, member) \
87 for ((elem) = CONTAINER_OF((list)->head.prev, typeof(*elem), member); &(elem)->member != &((list)->head); \
88 (elem) = CONTAINER_OF((elem)->member.prev, typeof(*elem), member))
89
90/**
91 * @brief Iterates over a list starting from a specific element.
92 *
93 * The `LIST_FOR_EACH_FROM()` macro iterates from a specific element, inclusive, until the end of the list.
94 *
95 * @param elem The loop variable, a pointer to the structure containing the list entry.
96 * @param start A pointer to the `list_entry_t` from which to start iteration.
97 * @param list A pointer to the `list_t` structure to iterate over.
98 * @param member The name of the `list_entry_t` member within the structure `elem`.
99 */
100#define LIST_FOR_EACH_FROM(elem, start, list, member) \
101 for ((elem) = CONTAINER_OF(start, typeof(*elem), member); &(elem)->member != &((list)->head); \
102 (elem) = CONTAINER_OF((elem)->member.next, typeof(*elem), member))
103
104/**
105 * @brief Iterates over a list in reverse order starting from a specific element.
106 *
107 * @param elem The loop variable, a pointer to the structure containing the list entry.
108 * @param start A pointer to the `list_entry_t` from which to start reverse iteration.
109 * @param list A pointer to the `list_t` structure to iterate over.
110 * @param member The name of the `list_entry_t` member within the structure `elem`.
111 */
112#define LIST_FOR_EACH_FROM_REVERSE(elem, start, list, member) \
113 for ((elem) = CONTAINER_OF(start, typeof(*elem), member); &(elem)->member != &((list)->head); \
114 (elem) = CONTAINER_OF((elem)->member.prev, typeof(*elem), member))
115
116/**
117 * @brief Iterates over a list up to a specific element.
118 *
119 * The `LIST_FOR_EACH_TO()` macro iterates from the start of the list, inclusive, until a specified element, not
120 * inclusive.
121 *
122 * @param elem The loop variable, a pointer to the structure containing the list entry.
123 * @param end A pointer to the `list_entry_t` at which to stop iteration (exclusive).
124 * @param list A pointer to the `list_t` structure to iterate over.
125 * @param member The name of the `list_entry_t` member within the structure `elem`.
126 */
127#define LIST_FOR_EACH_TO(elem, end, list, member) \
128 for ((elem) = CONTAINER_OF((list)->head.next, typeof(*elem), member); \
129 &(elem)->member != &((list)->head) && &(elem)->member != (end); \
130 (elem) = CONTAINER_OF((elem)->member.next, typeof(*elem), member))
131
132/**
133 * @brief Iterates over a list in reverse order up to a specific element.
134 *
135 * @param elem The loop variable, a pointer to the structure containing the list entry.
136 * @param end A pointer to the `list_entry_t` at which to stop reverse iteration (exclusive).
137 * @param list A pointer to the `list_t` structure to iterate over.
138 * @param member The name of the `list_entry_t` member within the structure `elem`.
139 */
140#define LIST_FOR_EACH_TO_REVERSE(elem, end, list, member) \
141 for ((elem) = CONTAINER_OF((list)->head.prev, typeof(*elem), member); \
142 &(elem)->member != &((list)->head) && &(elem)->member != (end); \
143 (elem) = CONTAINER_OF((elem)->member.prev, typeof(*elem), member))
144
145/**
146 * @brief Creates a list entry initializer.
147 *
148 * @param name The name of the entry variable to initialize.
149 * @return A `list_entry_t` initializer for the specified entry variable.
150 */
151#define LIST_ENTRY_CREATE(name) \
152 (list_entry_t) \
153 { \
154 .prev = &(name), .next = &(name), \
155 }
156
157/**
158 * @brief Creates a list initializer.
159 *
160 * @param name The name of the list variable to initialize.
161 * @return A `list_t` initializer for the specified list variable.
162 */
163#define LIST_CREATE(name) \
164 { \
165 .head = {.prev = &(name).head, .next = &(name).head } \
166 }
167
168/**
169 * @brief Initializes a list entry.
170 *
171 * @param entry A pointer to the `list_entry_t` to initialize.
172 */
173static inline void list_entry_init(list_entry_t* entry)
174{
175 assert(entry != NULL);
176 entry->next = entry;
177 entry->prev = entry;
178}
179
180/**
181 * @brief Initializes a list.
182 *
183 * @param list A pointer to the `list_t` to initialize.
184 */
185static inline void list_init(list_t* list)
186{
187 assert(list != NULL);
188 list_entry_init(&list->head);
189}
190
191/**
192 * @brief Check if an entry is in a list.
193 *
194 * @param entry A pointer to the `list_entry_t` to check.
195 * @return `true` if the entry is in a list, `false` otherwise.
196 */
197static inline bool list_entry_in_list(list_entry_t* entry)
198{
199 assert(entry != NULL);
200
201 return entry->next != entry && entry->prev != entry;
202}
203
204/**
205 * @brief Checks if a list is empty.
206 *
207 * @param list A pointer to the `list_t` to check.
208 * @return `true` if the list is empty, `false` otherwise.
209 */
210static inline bool list_is_empty(list_t* list)
211{
212 assert(list != NULL);
213
214 return list->head.next == &list->head;
215}
216
217/**
218 * @brief Adds a new element between two existing list entries.
219 *
220 * @param prev A pointer to the list entry that will precede the new element.
221 * @param next A pointer to the list entry that will follow the new element.
222 * @param elem A pointer to the `list_entry_t` to add.
223 */
224static inline void list_add(list_entry_t* prev, list_entry_t* next, list_entry_t* entry)
225{
226 assert(prev != NULL);
227 assert(next != NULL);
228 assert(entry != NULL);
229 assert(entry->next == entry && entry->prev == entry);
230 assert(prev->next == next && next->prev == prev);
231
232 next->prev = entry;
233 entry->next = next;
234 entry->prev = prev;
235 prev->next = entry;
236}
237
238/**
239 * @brief Adds a new element between two existing list entries in a RCU-safe manner.
240 *
241 * @param prev A pointer to the list entry that will precede the new element.
242 * @param next A pointer to the list entry that will follow the new element.
243 * @param elem A pointer to the `list_entry_t` to add.
244 */
245static inline void list_add_rcu(list_entry_t* prev, list_entry_t* next, list_entry_t* entry)
246{
247 assert(prev != NULL);
248 assert(next != NULL);
249 assert(entry != NULL);
250 // For RCU we allow adding an entry that is already in a list
251 // as we cant properly remove it until all readers are done.
252 // assert(entry->next == entry && entry->prev == entry);
253 // assert(prev->next == next && next->prev == prev);
254
255 next->prev = entry;
256 entry->next = next;
257 entry->prev = prev;
259 prev->next = entry;
260}
261
262/**
263 * @brief Appends an entry to the list.
264 *
265 * @param prev A pointer to the list entry after which the new entry will be appended.
266 * @param entry A pointer to the `list_entry_t` to append.
267 */
268static inline void list_append(list_entry_t* prev, list_entry_t* entry)
269{
270 list_add(prev, prev->next, entry);
271}
272
273/**
274 * @brief Prepends an entry to the list.
275 *
276 * @param list A pointer to the `list_t` to prepend to.
277 * @param head A pointer to the list entry before which the new entry will be prepended.
278 * @param entry A pointer to the `list_entry_t` to prepend.
279 */
280static inline void list_prepend(list_entry_t* head, list_entry_t* entry)
281{
282 list_add(head->prev, head, entry);
283}
284
285/**
286 * @brief Removes a list entry from its current list.
287 *
288 * @param entry A pointer to the `list_entry_t` to remove.
289 */
290static inline void list_remove(list_entry_t* entry)
291{
292 assert(entry != NULL);
293
294 entry->prev->next = entry->next;
295 entry->next->prev = entry->prev;
296 list_entry_init(entry);
297}
298
299/**
300 * @brief Removes a list entry from its current list in a RCU-safe manner.
301 *
302 * @warning After calling this function the entry will still be connected to the list, but iteration over the list will
303 * not find it.
304 *
305 * @param entry A pointer to the `list_entry_t` to remove.
306 */
307static inline void list_remove_rcu(list_entry_t* entry)
308{
309 assert(entry != NULL);
310
311 entry->prev->next = entry->next;
313 entry->next->prev = entry->prev;
314}
315
316/**
317 * @brief Pushes an entry to the end of the list.
318 *
319 * @param list A pointer to the `list_t` to push the entry to.
320 * @param entry A pointer to the `list_entry_t` to push.
321 */
322static inline void list_push_back(list_t* list, list_entry_t* entry)
323{
324 assert(list != NULL);
325 assert(entry != NULL);
326 assert(entry->next == entry && entry->prev == entry);
327
328 list_add(list->head.prev, &list->head, entry);
329}
330
331/**
332 * @brief Pushes an entry to the end of the list in a RCU-safe manner.
333 *
334 * @param list A pointer to the `list_t` to push the entry to.
335 * @param entry A pointer to the `list_entry_t` to push.
336 */
337static inline void list_push_back_rcu(list_t* list, list_entry_t* entry)
338{
339 assert(list != NULL);
340 assert(entry != NULL);
341
342 list_add_rcu(list->head.prev, &list->head, entry);
343}
344
345/**
346 * @brief Pushes an entry to the front of the list.
347 *
348 * @param list A pointer to the `list_t` to push the entry to.
349 * @param entry A pointer to the `list_entry_t` to push.
350 */
351static inline void list_push_front(list_t* list, list_entry_t* entry)
352{
353 assert(list != NULL);
354 assert(entry != NULL);
355 assert(entry->next == entry && entry->prev == entry);
356
357 list_add(&list->head, list->head.next, entry);
358}
359
360/**
361 * @brief Pops the first entry from the list.
362 *
363 * @param list A pointer to the `list_t` to pop the entry from.
364 * @return A pointer to the removed `list_entry_t`, or `NULL` if the list is empty.
365 */
366static inline list_entry_t* list_pop_front(list_t* list)
367{
368 assert(list != NULL);
369
370 if (list_is_empty(list))
371 {
372 return NULL;
373 }
374
375 list_entry_t* entry = list->head.next;
376 list_remove(entry);
377 return entry;
378}
379
380/**
381 * @brief Pops the last entry from the list.
382 *
383 * @param list A pointer to the `list_t` to pop the entry from.
384 * @return A pointer to the removed `list_entry_t`, or `NULL` if the list is empty.
385 */
386static inline list_entry_t* list_pop_back(list_t* list)
387{
388 assert(list != NULL);
389
390 if (list_is_empty(list))
391 {
392 return NULL;
393 }
394
395 list_entry_t* entry = list->head.prev;
396 list_remove(entry);
397 return entry;
398}
399
400/**
401 * @brief Gets the first entry in the list without removing it.
402 *
403 * @param list A pointer to the `list_t`.
404 * @return A pointer to the first `list_entry_t` in the list, or `NULL` if the list is empty.
405 */
406static inline list_entry_t* list_first(list_t* list)
407{
408 assert(list != NULL);
409
410 if (list_is_empty(list))
411 {
412 return NULL;
413 }
414 return list->head.next;
415}
416
417/**
418 * @brief Gets the last entry in the list without removing it.
419 *
420 * @param list A pointer to the `list_t`.
421 * @return A pointer to the last `list_entry_t` in the list, or `NULL` if the list is empty.
422 */
423static inline list_entry_t* list_last(list_t* list)
424{
425 assert(list != NULL);
426
427 if (list_is_empty(list))
428 {
429 return NULL;
430 }
431 return list->head.prev;
432}
433
434/**
435 * @brief Gets the next entry in the list relative to a given entry.
436 *
437 * @param list A pointer to the `list_t`.
438 * @param entry A pointer to the `list_entry_t` to get the next entry from.
439 * @return A pointer to the next `list_entry_t` in the list, or `NULL` if the given entry is the last.
440 */
441static inline list_entry_t* list_next(list_t* list, list_entry_t* entry)
442{
443 assert(list != NULL);
444 assert(entry != NULL);
445
446 if (entry->next == &list->head)
447 {
448 return NULL;
449 }
450 return entry->next;
451}
452
453/**
454 * @brief Gets the previous entry in the list relative to a given entry.
455 *
456 * @param list A pointer to the `list_t`.
457 * @param entry A pointer to the `list_entry_t` to get the previous entry from.
458 * @return A pointer to the previous `list_entry_t` in the list, or `NULL` if the given entry is the first.
459 */
460static inline list_entry_t* list_prev(list_t* list, list_entry_t* entry)
461{
462 assert(list != NULL);
463 assert(entry != NULL);
464
465 if (entry->prev == &list->head)
466 {
467 return NULL;
468 }
469 return entry->prev;
470}
471
472/**
473 * @brief Gets the size of the list.
474 *
475 * @param list A pointer to the `list_t`.
476 * @return The number of entries in the list.
477 */
478static inline uint64_t list_size(list_t* list)
479{
480 uint64_t size = 0;
481 list_entry_t* entry = list->head.next;
482 while (entry != &list->head)
483 {
484 size++;
485 entry = entry->next;
486 }
487 return size;
488}
489
490#endif
491
492/** @} */
#define assert(expression)
Definition assert.h:29
static void list_remove(list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:290
static list_entry_t * list_next(list_t *list, list_entry_t *entry)
Gets the next entry in the list relative to a given entry.
Definition list.h:441
static list_entry_t * list_first(list_t *list)
Gets the first entry in the list without removing it.
Definition list.h:406
static list_entry_t * list_last(list_t *list)
Gets the last entry in the list without removing it.
Definition list.h:423
static void list_push_back(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:322
static void list_prepend(list_entry_t *head, list_entry_t *entry)
Prepends an entry to the list.
Definition list.h:280
static bool list_entry_in_list(list_entry_t *entry)
Check if an entry is in a list.
Definition list.h:197
static void list_add_rcu(list_entry_t *prev, list_entry_t *next, list_entry_t *entry)
Adds a new element between two existing list entries in a RCU-safe manner.
Definition list.h:245
static list_entry_t * list_prev(list_t *list, list_entry_t *entry)
Gets the previous entry in the list relative to a given entry.
Definition list.h:460
static void list_append(list_entry_t *prev, list_entry_t *entry)
Appends an entry to the list.
Definition list.h:268
static void list_remove_rcu(list_entry_t *entry)
Removes a list entry from its current list in a RCU-safe manner.
Definition list.h:307
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:210
static uint64_t list_size(list_t *list)
Gets the size of the list.
Definition list.h:478
static list_entry_t * list_pop_back(list_t *list)
Pops the last entry from the list.
Definition list.h:386
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:173
static void list_push_back_rcu(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list in a RCU-safe manner.
Definition list.h:337
static void list_add(list_entry_t *prev, list_entry_t *next, list_entry_t *entry)
Adds a new element between two existing list entries.
Definition list.h:224
static void list_push_front(list_t *list, list_entry_t *entry)
Pushes an entry to the front of the list.
Definition list.h:351
static list_entry_t * list_pop_front(list_t *list)
Pops the first entry from the list.
Definition list.h:366
static void list_init(list_t *list)
Initializes a list.
Definition list.h:185
#define NULL
Pointer error value.
Definition NULL.h:25
static atomic_long next
Definition main.c:12
@ memory_order_release
Definition stdatomic.h:119
#define atomic_thread_fence(order)
Definition stdatomic.h:135
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
A entry in a doubly linked list.
Definition list.h:37
struct list_entry * next
The next entry in the list.
Definition list.h:39
struct list_entry * prev
The previous entry in the list.
Definition list.h:38
A doubly linked list.
Definition list.h:46
list_entry_t head
Definition list.h:47