1 /*
2 * Copyright (c) 2013-2015 Wind River Systems, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief Doubly-linked list implementation
10 *
11 * Doubly-linked list implementation using inline macros/functions.
12 * This API is not thread safe, and thus if a list is used across threads,
13 * calls to functions must be protected with synchronization primitives.
14 *
15 * The lists are expected to be initialized such that both the head and tail
16 * pointers point to the list itself. Initializing the lists in such a fashion
17 * simplifies the adding and removing of nodes to/from the list.
18 */
19
20 #ifndef ZEPHYR_INCLUDE_SYS_DLIST_H_
21 #define ZEPHYR_INCLUDE_SYS_DLIST_H_
22
23 #include <stddef.h>
24 #include <stdbool.h>
25 #include <toolchain.h>
26
27 #ifdef __cplusplus
28 extern "C" {
29 #endif
30
31 /**
32 * @defgroup doubly-linked-list_apis Doubly-linked list
33 * @ingroup datastructure_apis
34 * @{
35 */
36
37 struct _dnode {
38 union {
39 struct _dnode *head; /* ptr to head of list (sys_dlist_t) */
40 struct _dnode *next; /* ptr to next node (sys_dnode_t) */
41 };
42 union {
43 struct _dnode *tail; /* ptr to tail of list (sys_dlist_t) */
44 struct _dnode *prev; /* ptr to previous node (sys_dnode_t) */
45 };
46 };
47
48 typedef struct _dnode sys_dlist_t;
49 typedef struct _dnode sys_dnode_t;
50
51
52 /**
53 * @brief Provide the primitive to iterate on a list
54 * Note: the loop is unsafe and thus __dn should not be removed
55 *
56 * User _MUST_ add the loop statement curly braces enclosing its own code:
57 *
58 * SYS_DLIST_FOR_EACH_NODE(l, n) {
59 * <user code>
60 * }
61 *
62 * This and other SYS_DLIST_*() macros are not thread safe.
63 *
64 * @param __dl A pointer on a sys_dlist_t to iterate on
65 * @param __dn A sys_dnode_t pointer to peek each node of the list
66 */
67 #define SYS_DLIST_FOR_EACH_NODE(__dl, __dn) \
68 for (__dn = sys_dlist_peek_head(__dl); __dn != NULL; \
69 __dn = sys_dlist_peek_next(__dl, __dn))
70
71 /**
72 * @brief Provide the primitive to iterate on a list, from a node in the list
73 * Note: the loop is unsafe and thus __dn should not be removed
74 *
75 * User _MUST_ add the loop statement curly braces enclosing its own code:
76 *
77 * SYS_DLIST_ITERATE_FROM_NODE(l, n) {
78 * <user code>
79 * }
80 *
81 * Like SYS_DLIST_FOR_EACH_NODE(), but __dn already contains a node in the list
82 * where to start searching for the next entry from. If NULL, it starts from
83 * the head.
84 *
85 * This and other SYS_DLIST_*() macros are not thread safe.
86 *
87 * @param __dl A pointer on a sys_dlist_t to iterate on
88 * @param __dn A sys_dnode_t pointer to peek each node of the list;
89 * it contains the starting node, or NULL to start from the head
90 */
91 #define SYS_DLIST_ITERATE_FROM_NODE(__dl, __dn) \
92 for (__dn = __dn ? sys_dlist_peek_next_no_check(__dl, __dn) \
93 : sys_dlist_peek_head(__dl); \
94 __dn != NULL; \
95 __dn = sys_dlist_peek_next(__dl, __dn))
96
97 /**
98 * @brief Provide the primitive to safely iterate on a list
99 * Note: __dn can be removed, it will not break the loop.
100 *
101 * User _MUST_ add the loop statement curly braces enclosing its own code:
102 *
103 * SYS_DLIST_FOR_EACH_NODE_SAFE(l, n, s) {
104 * <user code>
105 * }
106 *
107 * This and other SYS_DLIST_*() macros are not thread safe.
108 *
109 * @param __dl A pointer on a sys_dlist_t to iterate on
110 * @param __dn A sys_dnode_t pointer to peek each node of the list
111 * @param __dns A sys_dnode_t pointer for the loop to run safely
112 */
113 #define SYS_DLIST_FOR_EACH_NODE_SAFE(__dl, __dn, __dns) \
114 for (__dn = sys_dlist_peek_head(__dl), \
115 __dns = sys_dlist_peek_next(__dl, __dn); \
116 __dn != NULL; __dn = __dns, \
117 __dns = sys_dlist_peek_next(__dl, __dn))
118
119 /*
120 * @brief Provide the primitive to resolve the container of a list node
121 * Note: it is safe to use with NULL pointer nodes
122 *
123 * @param __dn A pointer on a sys_dnode_t to get its container
124 * @param __cn Container struct type pointer
125 * @param __n The field name of sys_dnode_t within the container struct
126 */
127 #define SYS_DLIST_CONTAINER(__dn, __cn, __n) \
128 ((__dn != NULL) ? CONTAINER_OF(__dn, __typeof__(*__cn), __n) : NULL)
129 /*
130 * @brief Provide the primitive to peek container of the list head
131 *
132 * @param __dl A pointer on a sys_dlist_t to peek
133 * @param __cn Container struct type pointer
134 * @param __n The field name of sys_dnode_t within the container struct
135 */
136 #define SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n) \
137 SYS_DLIST_CONTAINER(sys_dlist_peek_head(__dl), __cn, __n)
138
139 /*
140 * @brief Provide the primitive to peek the next container
141 *
142 * @param __dl A pointer on a sys_dlist_t to peek
143 * @param __cn Container struct type pointer
144 * @param __n The field name of sys_dnode_t within the container struct
145 */
146 #define SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n) \
147 ((__cn != NULL) ? \
148 SYS_DLIST_CONTAINER(sys_dlist_peek_next(__dl, &(__cn->__n)), \
149 __cn, __n) : NULL)
150
151 /**
152 * @brief Provide the primitive to iterate on a list under a container
153 * Note: the loop is unsafe and thus __cn should not be detached
154 *
155 * User _MUST_ add the loop statement curly braces enclosing its own code:
156 *
157 * SYS_DLIST_FOR_EACH_CONTAINER(l, c, n) {
158 * <user code>
159 * }
160 *
161 * @param __dl A pointer on a sys_dlist_t to iterate on
162 * @param __cn A pointer to peek each entry of the list
163 * @param __n The field name of sys_dnode_t within the container struct
164 */
165 #define SYS_DLIST_FOR_EACH_CONTAINER(__dl, __cn, __n) \
166 for (__cn = SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n); \
167 __cn != NULL; \
168 __cn = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n))
169
170 /**
171 * @brief Provide the primitive to safely iterate on a list under a container
172 * Note: __cn can be detached, it will not break the loop.
173 *
174 * User _MUST_ add the loop statement curly braces enclosing its own code:
175 *
176 * SYS_DLIST_FOR_EACH_CONTAINER_SAFE(l, c, cn, n) {
177 * <user code>
178 * }
179 *
180 * @param __dl A pointer on a sys_dlist_t to iterate on
181 * @param __cn A pointer to peek each entry of the list
182 * @param __cns A pointer for the loop to run safely
183 * @param __n The field name of sys_dnode_t within the container struct
184 */
185 #define SYS_DLIST_FOR_EACH_CONTAINER_SAFE(__dl, __cn, __cns, __n) \
186 for (__cn = SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n), \
187 __cns = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n); \
188 __cn != NULL; __cn = __cns, \
189 __cns = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n))
190
191 /**
192 * @brief initialize list to its empty state
193 *
194 * @param list the doubly-linked list
195 *
196 * @return N/A
197 */
198
sys_dlist_init(sys_dlist_t * list)199 static inline void sys_dlist_init(sys_dlist_t *list)
200 {
201 list->head = (sys_dnode_t *)list;
202 list->tail = (sys_dnode_t *)list;
203 }
204
205 #define SYS_DLIST_STATIC_INIT(ptr_to_list) { {(ptr_to_list)}, {(ptr_to_list)} }
206
207 /**
208 * @brief initialize node to its state when not in a list
209 *
210 * @param node the node
211 *
212 * @return N/A
213 */
214
sys_dnode_init(sys_dnode_t * node)215 static inline void sys_dnode_init(sys_dnode_t *node)
216 {
217 node->next = NULL;
218 node->prev = NULL;
219 }
220
221 /**
222 * @brief check if a node is a member of any list
223 *
224 * @param node the node
225 *
226 * @return true if node is linked into a list, false if it is not
227 */
228
sys_dnode_is_linked(const sys_dnode_t * node)229 static inline bool sys_dnode_is_linked(const sys_dnode_t *node)
230 {
231 return node->next != NULL;
232 }
233
234 /**
235 * @brief check if a node is the list's head
236 *
237 * @param list the doubly-linked list to operate on
238 * @param node the node to check
239 *
240 * @return true if node is the head, false otherwise
241 */
242
sys_dlist_is_head(sys_dlist_t * list,sys_dnode_t * node)243 static inline bool sys_dlist_is_head(sys_dlist_t *list, sys_dnode_t *node)
244 {
245 return list->head == node;
246 }
247
248 /**
249 * @brief check if a node is the list's tail
250 *
251 * @param list the doubly-linked list to operate on
252 * @param node the node to check
253 *
254 * @return true if node is the tail, false otherwise
255 */
256
sys_dlist_is_tail(sys_dlist_t * list,sys_dnode_t * node)257 static inline bool sys_dlist_is_tail(sys_dlist_t *list, sys_dnode_t *node)
258 {
259 return list->tail == node;
260 }
261
262 /**
263 * @brief check if the list is empty
264 *
265 * @param list the doubly-linked list to operate on
266 *
267 * @return true if empty, false otherwise
268 */
269
sys_dlist_is_empty(sys_dlist_t * list)270 static inline bool sys_dlist_is_empty(sys_dlist_t *list)
271 {
272 return list->head == list;
273 }
274
275 /**
276 * @brief check if more than one node present
277 *
278 * This and other sys_dlist_*() functions are not thread safe.
279 *
280 * @param list the doubly-linked list to operate on
281 *
282 * @return true if multiple nodes, false otherwise
283 */
284
sys_dlist_has_multiple_nodes(sys_dlist_t * list)285 static inline bool sys_dlist_has_multiple_nodes(sys_dlist_t *list)
286 {
287 return list->head != list->tail;
288 }
289
290 /**
291 * @brief get a reference to the head item in the list
292 *
293 * @param list the doubly-linked list to operate on
294 *
295 * @return a pointer to the head element, NULL if list is empty
296 */
297
sys_dlist_peek_head(sys_dlist_t * list)298 static inline sys_dnode_t *sys_dlist_peek_head(sys_dlist_t *list)
299 {
300 return sys_dlist_is_empty(list) ? NULL : list->head;
301 }
302
303 /**
304 * @brief get a reference to the head item in the list
305 *
306 * The list must be known to be non-empty.
307 *
308 * @param list the doubly-linked list to operate on
309 *
310 * @return a pointer to the head element
311 */
312
sys_dlist_peek_head_not_empty(sys_dlist_t * list)313 static inline sys_dnode_t *sys_dlist_peek_head_not_empty(sys_dlist_t *list)
314 {
315 return list->head;
316 }
317
318 /**
319 * @brief get a reference to the next item in the list, node is not NULL
320 *
321 * Faster than sys_dlist_peek_next() if node is known not to be NULL.
322 *
323 * @param list the doubly-linked list to operate on
324 * @param node the node from which to get the next element in the list
325 *
326 * @return a pointer to the next element from a node, NULL if node is the tail
327 */
328
sys_dlist_peek_next_no_check(sys_dlist_t * list,sys_dnode_t * node)329 static inline sys_dnode_t *sys_dlist_peek_next_no_check(sys_dlist_t *list,
330 sys_dnode_t *node)
331 {
332 return (node == list->tail) ? NULL : node->next;
333 }
334
335 /**
336 * @brief get a reference to the next item in the list
337 *
338 * @param list the doubly-linked list to operate on
339 * @param node the node from which to get the next element in the list
340 *
341 * @return a pointer to the next element from a node, NULL if node is the tail
342 * or NULL (when node comes from reading the head of an empty list).
343 */
344
sys_dlist_peek_next(sys_dlist_t * list,sys_dnode_t * node)345 static inline sys_dnode_t *sys_dlist_peek_next(sys_dlist_t *list,
346 sys_dnode_t *node)
347 {
348 return (node != NULL) ? sys_dlist_peek_next_no_check(list, node) : NULL;
349 }
350
351 /**
352 * @brief get a reference to the previous item in the list, node is not NULL
353 *
354 * Faster than sys_dlist_peek_prev() if node is known not to be NULL.
355 *
356 * @param list the doubly-linked list to operate on
357 * @param node the node from which to get the previous element in the list
358 *
359 * @return a pointer to the previous element from a node, NULL if node is the
360 * tail
361 */
362
sys_dlist_peek_prev_no_check(sys_dlist_t * list,sys_dnode_t * node)363 static inline sys_dnode_t *sys_dlist_peek_prev_no_check(sys_dlist_t *list,
364 sys_dnode_t *node)
365 {
366 return (node == list->head) ? NULL : node->prev;
367 }
368
369 /**
370 * @brief get a reference to the previous item in the list
371 *
372 * @param list the doubly-linked list to operate on
373 * @param node the node from which to get the previous element in the list
374 *
375 * @return a pointer to the previous element from a node, NULL if node is the
376 * tail or NULL (when node comes from reading the head of an empty
377 * list).
378 */
379
sys_dlist_peek_prev(sys_dlist_t * list,sys_dnode_t * node)380 static inline sys_dnode_t *sys_dlist_peek_prev(sys_dlist_t *list,
381 sys_dnode_t *node)
382 {
383 return (node != NULL) ? sys_dlist_peek_prev_no_check(list, node) : NULL;
384 }
385
386 /**
387 * @brief get a reference to the tail item in the list
388 *
389 * @param list the doubly-linked list to operate on
390 *
391 * @return a pointer to the tail element, NULL if list is empty
392 */
393
sys_dlist_peek_tail(sys_dlist_t * list)394 static inline sys_dnode_t *sys_dlist_peek_tail(sys_dlist_t *list)
395 {
396 return sys_dlist_is_empty(list) ? NULL : list->tail;
397 }
398
399 /**
400 * @brief add node to tail of list
401 *
402 * This and other sys_dlist_*() functions are not thread safe.
403 *
404 * @param list the doubly-linked list to operate on
405 * @param node the element to append
406 *
407 * @return N/A
408 */
409
sys_dlist_append(sys_dlist_t * list,sys_dnode_t * node)410 static inline void sys_dlist_append(sys_dlist_t *list, sys_dnode_t *node)
411 {
412 sys_dnode_t *const tail = list->tail;
413
414 node->next = list;
415 node->prev = tail;
416
417 tail->next = node;
418 list->tail = node;
419 }
420
421 /**
422 * @brief add node to head of list
423 *
424 * This and other sys_dlist_*() functions are not thread safe.
425 *
426 * @param list the doubly-linked list to operate on
427 * @param node the element to append
428 *
429 * @return N/A
430 */
431
sys_dlist_prepend(sys_dlist_t * list,sys_dnode_t * node)432 static inline void sys_dlist_prepend(sys_dlist_t *list, sys_dnode_t *node)
433 {
434 sys_dnode_t *const head = list->head;
435
436 node->next = head;
437 node->prev = list;
438
439 head->prev = node;
440 list->head = node;
441 }
442
443 /**
444 * @brief Insert a node into a list
445 *
446 * Insert a node before a specified node in a dlist.
447 *
448 * @param successor the position before which "node" will be inserted
449 * @param node the element to insert
450 */
sys_dlist_insert(sys_dnode_t * successor,sys_dnode_t * node)451 static inline void sys_dlist_insert(sys_dnode_t *successor, sys_dnode_t *node)
452 {
453 sys_dnode_t *const prev = successor->prev;
454
455 node->prev = prev;
456 node->next = successor;
457 prev->next = node;
458 successor->prev = node;
459 }
460
461 /**
462 * @brief insert node at position
463 *
464 * Insert a node in a location depending on a external condition. The cond()
465 * function checks if the node is to be inserted _before_ the current node
466 * against which it is checked.
467 * This and other sys_dlist_*() functions are not thread safe.
468 *
469 * @param list the doubly-linked list to operate on
470 * @param node the element to insert
471 * @param cond a function that determines if the current node is the correct
472 * insert point
473 * @param data parameter to cond()
474 *
475 * @return N/A
476 */
477
sys_dlist_insert_at(sys_dlist_t * list,sys_dnode_t * node,int (* cond)(sys_dnode_t * node,void * data),void * data)478 static inline void sys_dlist_insert_at(sys_dlist_t *list, sys_dnode_t *node,
479 int (*cond)(sys_dnode_t *node, void *data), void *data)
480 {
481 if (sys_dlist_is_empty(list)) {
482 sys_dlist_append(list, node);
483 } else {
484 sys_dnode_t *pos = sys_dlist_peek_head(list);
485
486 while ((pos != NULL) && (cond(pos, data) == 0)) {
487 pos = sys_dlist_peek_next(list, pos);
488 }
489 if (pos != NULL) {
490 sys_dlist_insert(pos, node);
491 } else {
492 sys_dlist_append(list, node);
493 }
494 }
495 }
496
497 /**
498 * @brief remove a specific node from a list
499 *
500 * The list is implicit from the node. The node must be part of a list.
501 * This and other sys_dlist_*() functions are not thread safe.
502 *
503 * @param node the node to remove
504 *
505 * @return N/A
506 */
507
sys_dlist_remove(sys_dnode_t * node)508 static inline void sys_dlist_remove(sys_dnode_t *node)
509 {
510 sys_dnode_t *const prev = node->prev;
511 sys_dnode_t *const next = node->next;
512
513 prev->next = next;
514 next->prev = prev;
515 sys_dnode_init(node);
516 }
517
518 /**
519 * @brief get the first node in a list
520 *
521 * This and other sys_dlist_*() functions are not thread safe.
522 *
523 * @param list the doubly-linked list to operate on
524 *
525 * @return the first node in the list, NULL if list is empty
526 */
527
sys_dlist_get(sys_dlist_t * list)528 static inline sys_dnode_t *sys_dlist_get(sys_dlist_t *list)
529 {
530 sys_dnode_t *node = NULL;
531
532 if (!sys_dlist_is_empty(list)) {
533 node = list->head;
534 sys_dlist_remove(node);
535 }
536
537 return node;
538 }
539
540 /** @} */
541
542 #ifdef __cplusplus
543 }
544 #endif
545
546 #endif /* ZEPHYR_INCLUDE_SYS_DLIST_H_ */
547