1 // SPDX-FileCopyrightText: 2002 Free Software Foundation, Inc. 2 // SPDX-FileCopyrightText: 2009 Pierre-Marc Fournier 3 // SPDX-FileCopyrightText: 2010 Mathieu Desnoyers <mathieu.desnoyers (at) efficios.com> 4 // 5 // SPDX-License-Identifier: LGPL-2.1-or-later 6 7 /* 8 * (originally part of the GNU C Library) 9 * Contributed by Ulrich Drepper <drepper (at) redhat.com>, 2002. 10 */ 11 12 #ifndef _CDS_LIST_H 13 #define _CDS_LIST_H 1 14 15 #include <urcu/compiler.h> 16 17 /* 18 * The definitions of this file are adopted from those which can be 19 * found in the Linux kernel headers to enable people familiar with the 20 * latter find their way in these sources as well. 21 */ 22 23 /* Basic type for the double-link list. */ 24 struct cds_list_head { 25 struct cds_list_head *next, *prev; 26 }; 27 28 /* Define a variable with the head and tail of the list. */ 29 #define CDS_LIST_HEAD(name) \ 30 struct cds_list_head name = { &(name), &(name) } 31 32 /* Initialize a new list head. */ 33 #define CDS_INIT_LIST_HEAD(ptr) \ 34 (ptr)->next = (ptr)->prev = (ptr) 35 36 #define CDS_LIST_HEAD_INIT(name) { .next = &(name), .prev = &(name) } 37 38 /* Add new element at the head of the list. */ 39 static inline 40 void cds_list_add(struct cds_list_head *newp, struct cds_list_head *head) 41 { 42 head->next->prev = newp; 43 newp->next = head->next; 44 newp->prev = head; 45 head->next = newp; 46 } 47 48 /* Add new element at the tail of the list. */ 49 static inline 50 void cds_list_add_tail(struct cds_list_head *newp, struct cds_list_head *head) 51 { 52 head->prev->next = newp; 53 newp->next = head; 54 newp->prev = head->prev; 55 head->prev = newp; 56 } 57 58 /* Remove element from list. */ 59 static inline 60 void __cds_list_del(struct cds_list_head *prev, struct cds_list_head *next) 61 { 62 next->prev = prev; 63 prev->next = next; 64 } 65 66 /* Remove element from list. */ 67 static inline 68 void cds_list_del(struct cds_list_head *elem) 69 { 70 __cds_list_del(elem->prev, elem->next); 71 } 72 73 /* Remove element from list, initializing the element's list pointers. */ 74 static inline 75 void cds_list_del_init(struct cds_list_head *elem) 76 { 77 cds_list_del(elem); 78 CDS_INIT_LIST_HEAD(elem); 79 } 80 81 /* Delete from list, add to another list as head. */ 82 static inline 83 void cds_list_move(struct cds_list_head *elem, struct cds_list_head *head) 84 { 85 __cds_list_del(elem->prev, elem->next); 86 cds_list_add(elem, head); 87 } 88 89 /* Replace an old entry. */ 90 static inline 91 void cds_list_replace(const struct cds_list_head *old, struct cds_list_head *_new) 92 { 93 _new->next = old->next; 94 _new->prev = old->prev; 95 _new->prev->next = _new; 96 _new->next->prev = _new; 97 } 98 99 /* Join two lists. */ 100 static inline 101 void cds_list_splice(struct cds_list_head *add, struct cds_list_head *head) 102 { 103 /* Do nothing if the list which gets added is empty. */ 104 if (add != add->next) { 105 add->next->prev = head; 106 add->prev->next = head->next; 107 head->next->prev = add->prev; 108 head->next = add->next; 109 } 110 } 111 112 /* Get typed element from list at a given position. */ 113 #define cds_list_entry(ptr, type, member) caa_container_of(ptr, type, member) 114 115 116 /* Get first entry from a list. */ 117 #define cds_list_first_entry(ptr, type, member) \ 118 cds_list_entry((ptr)->next, type, member) 119 120 /* Iterate forward over the elements of the list. */ 121 #define cds_list_for_each(pos, head) \ 122 for (pos = (head)->next; (pos) != (head); pos = (pos)->next) 123 124 /* 125 * Iterate forward over the elements list. The list elements can be 126 * removed from the list while doing this. 127 */ 128 #define cds_list_for_each_safe(pos, p, head) \ 129 for (pos = (head)->next, p = (pos)->next; \ 130 (pos) != (head); \ 131 pos = (p), p = (pos)->next) 132 133 /* Iterate backward over the elements of the list. */ 134 #define cds_list_for_each_prev(pos, head) \ 135 for (pos = (head)->prev; (pos) != (head); pos = (pos)->prev) 136 137 /* 138 * Iterate backwards over the elements list. The list elements can be 139 * removed from the list while doing this. 140 */ 141 #define cds_list_for_each_prev_safe(pos, p, head) \ 142 for (pos = (head)->prev, p = (pos)->prev; \ 143 (pos) != (head); \ 144 pos = (p), p = (pos)->prev) 145 146 #define cds_list_for_each_entry(pos, head, member) \ 147 for (pos = cds_list_entry((head)->next, __typeof__(*(pos)), member); \ 148 &(pos)->member != (head); \ 149 pos = cds_list_entry((pos)->member.next, __typeof__(*(pos)), member)) 150 151 #define cds_list_for_each_entry_reverse(pos, head, member) \ 152 for (pos = cds_list_entry((head)->prev, __typeof__(*(pos)), member); \ 153 &(pos)->member != (head); \ 154 pos = cds_list_entry((pos)->member.prev, __typeof__(*(pos)), member)) 155 156 #define cds_list_for_each_entry_safe(pos, p, head, member) \ 157 for (pos = cds_list_entry((head)->next, __typeof__(*(pos)), member), \ 158 p = cds_list_entry((pos)->member.next, __typeof__(*(pos)), member); \ 159 &(pos)->member != (head); \ 160 pos = (p), p = cds_list_entry((pos)->member.next, __typeof__(*(pos)), member)) 161 162 /* 163 * Same as cds_list_for_each_entry_safe, but starts from "pos" which should 164 * point to an entry within the list. 165 */ 166 #define cds_list_for_each_entry_safe_from(pos, p, head, member) \ 167 for (p = cds_list_entry((pos)->member.next, __typeof__(*(pos)), member); \ 168 &(pos)->member != (head); \ 169 pos = (p), p = cds_list_entry((pos)->member.next, __typeof__(*(pos)), member)) 170 171 static inline 172 int cds_list_empty(const struct cds_list_head *head) 173 { 174 return head == head->next; 175 } 176 177 static inline 178 void cds_list_replace_init(struct cds_list_head *old, 179 struct cds_list_head *_new) 180 { 181 struct cds_list_head *head = old->next; 182 183 cds_list_del(old); 184 cds_list_add_tail(_new, head); 185 CDS_INIT_LIST_HEAD(old); 186 } 187 188 #endif /* _CDS_LIST_H */ 189