/src/openvswitch/lib/rculist.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2008, 2009, 2010, 2011, 2013, 2014 Nicira, Inc. |
3 | | * |
4 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | * you may not use this file except in compliance with the License. |
6 | | * You may obtain a copy of the License at: |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | #ifndef RCULIST_H |
17 | | #define RCULIST_H 1 |
18 | | |
19 | | /* A single writer multiple RCU-reader doubly linked list. |
20 | | * |
21 | | * RCU readers may iterate over the list at the same time as a writer is |
22 | | * modifying the list. Multiple writers can be supported by use of mutual |
23 | | * exclusion, but rculist does not provide that, as the user of rculist |
24 | | * typically does that already. |
25 | | * |
26 | | * To be RCU-friendly, the struct rculist instances must be freed via |
27 | | * ovsrcu_postpone(). |
28 | | * |
29 | | * The API is almost the same as for struct ovs_list, with the following |
30 | | * exceptions: |
31 | | * |
32 | | * - The 'prev' pointer may not be accessed by the user. |
33 | | * - The 'next' pointer should be accessed via rculist_next() by readers, and |
34 | | * rculist_next_protected() by the writer. |
35 | | * - No rculist_moved(): due to the memory management limitation stated above, |
36 | | * rculist instances may not be reallocated, as realloc may instantly free |
37 | | * the old memory. |
38 | | * - rculist_front() returns a const pointer to accommodate for an RCU reader. |
39 | | * - rculist_splice_hidden(): Spliced elements may not have been visible to |
40 | | * RCU readers before the operation. |
41 | | * - rculist_poison(): Only poisons the 'prev' pointer. |
42 | | * |
43 | | * The following functions are variations of the struct ovs_list functions with |
44 | | * similar names, but are now restricted to the writer use: |
45 | | * |
46 | | * - rculist_back_protected() |
47 | | * - rculist_is_short_protected() |
48 | | * - rculist_is_singleton_protected() |
49 | | */ |
50 | | |
51 | | #include <stdbool.h> |
52 | | #include <stddef.h> |
53 | | #include "ovs-rcu.h" |
54 | | #include "util.h" |
55 | | |
56 | | /* A non-existing mutex to make it more difficult for an user to accidentally |
57 | | * keep using the 'prev' pointer. This may be helpful when porting code from |
58 | | * struct ovs_list to rculist. */ |
59 | | extern struct ovs_mutex rculist_fake_mutex; |
60 | | |
61 | | /* Doubly linked list head or element. */ |
62 | | struct rculist { |
63 | | /* Previous list element. */ |
64 | | struct rculist *prev OVS_GUARDED_BY(rculist_fake_mutex); |
65 | | |
66 | | /* Next list element. */ |
67 | | OVSRCU_TYPE(struct rculist *) next; |
68 | | }; |
69 | | |
70 | | /* Easier access to 'next' member. */ |
71 | | static inline const struct rculist *rculist_next(const struct rculist *); |
72 | | static inline struct rculist *rculist_next_protected(const struct rculist *); |
73 | | |
74 | | /* List initialization. */ |
75 | | #define RCUOVS_LIST_INITIALIZER(LIST) { LIST, OVSRCU_INITIALIZER(LIST) } |
76 | | |
77 | | static inline void rculist_init(struct rculist *list); |
78 | | static inline void rculist_poison(struct rculist *elem); |
79 | | |
80 | | /* List insertion. */ |
81 | | static inline void rculist_insert(struct rculist *list, struct rculist *elem); |
82 | | static inline void rculist_splice_hidden(struct rculist *before, |
83 | | struct rculist *first, |
84 | | struct rculist *last); |
85 | | static inline void rculist_push_front(struct rculist *list, |
86 | | struct rculist *elem); |
87 | | static inline void rculist_push_back(struct rculist *list, |
88 | | struct rculist *elem); |
89 | | static inline void rculist_replace(struct rculist *replacement, |
90 | | struct rculist *replaced); |
91 | | static inline void rculist_move(struct rculist *dst, struct rculist *src); |
92 | | |
93 | | /* List removal. */ |
94 | | static inline struct rculist *rculist_remove(struct rculist *elem); |
95 | | static inline struct rculist *rculist_pop_front(struct rculist *list); |
96 | | static inline struct rculist *rculist_pop_back(struct rculist *list); |
97 | | |
98 | | /* List elements. */ |
99 | | static inline const struct rculist *rculist_front(const struct rculist *); |
100 | | static inline struct rculist *rculist_back_protected(const struct rculist *); |
101 | | |
102 | | /* List properties. */ |
103 | | static inline size_t rculist_size(const struct rculist *); |
104 | | static inline bool rculist_is_empty(const struct rculist *); |
105 | | static inline bool rculist_is_singleton_protected(const struct rculist *); |
106 | | static inline bool rculist_is_short_protected(const struct rculist *); |
107 | | |
108 | | |
109 | | /* Inline implementations. */ |
110 | | |
111 | | static inline const struct rculist * |
112 | | rculist_next(const struct rculist *list) |
113 | 0 | { |
114 | 0 | return ovsrcu_get(struct rculist *, &list->next); |
115 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_next Unexecuted instantiation: nx-match.c:rculist_next Unexecuted instantiation: ofp-util.c:rculist_next Unexecuted instantiation: ovs-router.c:rculist_next Unexecuted instantiation: tnl-ports.c:rculist_next Unexecuted instantiation: classifier.c:rculist_next Unexecuted instantiation: conntrack.c:rculist_next Unexecuted instantiation: conntrack-icmp.c:rculist_next Unexecuted instantiation: conntrack-tcp.c:rculist_next Unexecuted instantiation: conntrack-tp.c:rculist_next Unexecuted instantiation: conntrack-other.c:rculist_next |
116 | | |
117 | | static inline struct rculist * |
118 | | rculist_next_protected(const struct rculist *list) |
119 | | |
120 | 0 | { |
121 | 0 | return ovsrcu_get_protected(struct rculist *, &list->next); |
122 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_next_protected Unexecuted instantiation: nx-match.c:rculist_next_protected Unexecuted instantiation: ofp-util.c:rculist_next_protected Unexecuted instantiation: ovs-router.c:rculist_next_protected Unexecuted instantiation: tnl-ports.c:rculist_next_protected Unexecuted instantiation: classifier.c:rculist_next_protected Unexecuted instantiation: conntrack.c:rculist_next_protected Unexecuted instantiation: conntrack-icmp.c:rculist_next_protected Unexecuted instantiation: conntrack-tcp.c:rculist_next_protected Unexecuted instantiation: conntrack-tp.c:rculist_next_protected Unexecuted instantiation: conntrack-other.c:rculist_next_protected |
123 | | |
124 | | static inline void |
125 | | rculist_init(struct rculist *list) |
126 | | OVS_NO_THREAD_SAFETY_ANALYSIS |
127 | 0 | { |
128 | 0 | list->prev = list; |
129 | 0 | ovsrcu_init(&list->next, list); |
130 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_init Unexecuted instantiation: nx-match.c:rculist_init Unexecuted instantiation: ofp-util.c:rculist_init Unexecuted instantiation: ovs-router.c:rculist_init Unexecuted instantiation: tnl-ports.c:rculist_init Unexecuted instantiation: classifier.c:rculist_init Unexecuted instantiation: conntrack.c:rculist_init Unexecuted instantiation: conntrack-icmp.c:rculist_init Unexecuted instantiation: conntrack-tcp.c:rculist_init Unexecuted instantiation: conntrack-tp.c:rculist_init Unexecuted instantiation: conntrack-other.c:rculist_init |
131 | | |
132 | 0 | #define RCULIST_POISON (struct rculist *)(UINTPTR_MAX / 0xf * 0xc) |
133 | | |
134 | | /* Initializes 'list' with pointers that will (probably) cause segfaults if |
135 | | * dereferenced and, better yet, show up clearly in a debugger. */ |
136 | | static inline void |
137 | | rculist_poison(struct rculist *list) |
138 | | OVS_NO_THREAD_SAFETY_ANALYSIS |
139 | 0 | { |
140 | 0 | list->prev = RCULIST_POISON; |
141 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_poison Unexecuted instantiation: nx-match.c:rculist_poison Unexecuted instantiation: ofp-util.c:rculist_poison Unexecuted instantiation: ovs-router.c:rculist_poison Unexecuted instantiation: tnl-ports.c:rculist_poison Unexecuted instantiation: classifier.c:rculist_poison Unexecuted instantiation: conntrack.c:rculist_poison Unexecuted instantiation: conntrack-icmp.c:rculist_poison Unexecuted instantiation: conntrack-tcp.c:rculist_poison Unexecuted instantiation: conntrack-tp.c:rculist_poison Unexecuted instantiation: conntrack-other.c:rculist_poison |
142 | | |
143 | | /* Initializes 'list' with pointers that will (probably) cause segfaults if |
144 | | * dereferenced and, better yet, show up clearly in a debugger. |
145 | | * |
146 | | * This variant poisons also the next pointer, so this may not be called if |
147 | | * this list element is still visible to RCU readers. */ |
148 | | static inline void |
149 | | rculist_poison__(struct rculist *list) |
150 | | OVS_NO_THREAD_SAFETY_ANALYSIS |
151 | 0 | { |
152 | 0 | rculist_poison(list); |
153 | 0 | ovsrcu_set_hidden(&list->next, RCULIST_POISON); |
154 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_poison__ Unexecuted instantiation: nx-match.c:rculist_poison__ Unexecuted instantiation: ofp-util.c:rculist_poison__ Unexecuted instantiation: ovs-router.c:rculist_poison__ Unexecuted instantiation: tnl-ports.c:rculist_poison__ Unexecuted instantiation: classifier.c:rculist_poison__ Unexecuted instantiation: conntrack.c:rculist_poison__ Unexecuted instantiation: conntrack-icmp.c:rculist_poison__ Unexecuted instantiation: conntrack-tcp.c:rculist_poison__ Unexecuted instantiation: conntrack-tp.c:rculist_poison__ Unexecuted instantiation: conntrack-other.c:rculist_poison__ |
155 | | |
156 | | /* rculist insertion. */ |
157 | | static inline void |
158 | | rculist_insert(struct rculist *before, struct rculist *elem) |
159 | | OVS_NO_THREAD_SAFETY_ANALYSIS |
160 | 0 | { |
161 | 0 | elem->prev = before->prev; |
162 | 0 | ovsrcu_set_hidden(&elem->next, before); |
163 | 0 | ovsrcu_set(&before->prev->next, elem); |
164 | 0 | before->prev = elem; |
165 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_insert Unexecuted instantiation: nx-match.c:rculist_insert Unexecuted instantiation: ofp-util.c:rculist_insert Unexecuted instantiation: ovs-router.c:rculist_insert Unexecuted instantiation: tnl-ports.c:rculist_insert Unexecuted instantiation: classifier.c:rculist_insert Unexecuted instantiation: conntrack.c:rculist_insert Unexecuted instantiation: conntrack-icmp.c:rculist_insert Unexecuted instantiation: conntrack-tcp.c:rculist_insert Unexecuted instantiation: conntrack-tp.c:rculist_insert Unexecuted instantiation: conntrack-other.c:rculist_insert |
166 | | |
167 | | /* Removes elements 'first' though 'last' (exclusive) from their current list, |
168 | | * which may NOT be visible to any other threads (== be hidden from them), |
169 | | * then inserts them just before 'before'. */ |
170 | | static inline void |
171 | | rculist_splice_hidden(struct rculist *before, struct rculist *first, |
172 | | struct rculist *last) |
173 | | OVS_NO_THREAD_SAFETY_ANALYSIS |
174 | 0 | { |
175 | 0 | struct rculist *last_next; |
176 | 0 |
|
177 | 0 | if (first == last) { |
178 | 0 | return; |
179 | 0 | } |
180 | 0 | last = last->prev; |
181 | 0 |
|
182 | 0 | /* Cleanly remove 'first'...'last' from its current list. */ |
183 | 0 | last_next = rculist_next_protected(last); |
184 | 0 | last_next->prev = first->prev; |
185 | 0 | ovsrcu_set_hidden(&first->prev->next, last_next); |
186 | 0 |
|
187 | 0 | /* Splice 'first'...'last' into new list. */ |
188 | 0 | first->prev = before->prev; |
189 | 0 | ovsrcu_set(&last->next, before); |
190 | 0 | ovsrcu_set(&before->prev->next, first); |
191 | 0 | before->prev = last; |
192 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_splice_hidden Unexecuted instantiation: nx-match.c:rculist_splice_hidden Unexecuted instantiation: ofp-util.c:rculist_splice_hidden Unexecuted instantiation: ovs-router.c:rculist_splice_hidden Unexecuted instantiation: tnl-ports.c:rculist_splice_hidden Unexecuted instantiation: classifier.c:rculist_splice_hidden Unexecuted instantiation: conntrack.c:rculist_splice_hidden Unexecuted instantiation: conntrack-icmp.c:rculist_splice_hidden Unexecuted instantiation: conntrack-tcp.c:rculist_splice_hidden Unexecuted instantiation: conntrack-tp.c:rculist_splice_hidden Unexecuted instantiation: conntrack-other.c:rculist_splice_hidden |
193 | | |
194 | | /* Inserts 'elem' at the beginning of 'list', so that it becomes the front in |
195 | | * 'list'. */ |
196 | | static inline void |
197 | | rculist_push_front(struct rculist *list, struct rculist *elem) |
198 | 0 | { |
199 | 0 | rculist_insert(rculist_next_protected(list), elem); |
200 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_push_front Unexecuted instantiation: nx-match.c:rculist_push_front Unexecuted instantiation: ofp-util.c:rculist_push_front Unexecuted instantiation: ovs-router.c:rculist_push_front Unexecuted instantiation: tnl-ports.c:rculist_push_front Unexecuted instantiation: classifier.c:rculist_push_front Unexecuted instantiation: conntrack.c:rculist_push_front Unexecuted instantiation: conntrack-icmp.c:rculist_push_front Unexecuted instantiation: conntrack-tcp.c:rculist_push_front Unexecuted instantiation: conntrack-tp.c:rculist_push_front Unexecuted instantiation: conntrack-other.c:rculist_push_front |
201 | | |
202 | | /* Inserts 'elem' at the end of 'list', so that it becomes the back in |
203 | | * 'list'. */ |
204 | | static inline void |
205 | | rculist_push_back(struct rculist *list, struct rculist *elem) |
206 | 0 | { |
207 | 0 | rculist_insert(list, elem); |
208 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_push_back Unexecuted instantiation: nx-match.c:rculist_push_back Unexecuted instantiation: ofp-util.c:rculist_push_back Unexecuted instantiation: ovs-router.c:rculist_push_back Unexecuted instantiation: tnl-ports.c:rculist_push_back Unexecuted instantiation: classifier.c:rculist_push_back Unexecuted instantiation: conntrack.c:rculist_push_back Unexecuted instantiation: conntrack-icmp.c:rculist_push_back Unexecuted instantiation: conntrack-tcp.c:rculist_push_back Unexecuted instantiation: conntrack-tp.c:rculist_push_back Unexecuted instantiation: conntrack-other.c:rculist_push_back |
209 | | |
210 | | /* Puts 'element' in the position currently occupied by 'position'. |
211 | | * |
212 | | * Afterward, 'position' is not linked to from the list any more, but still |
213 | | * links to the nodes in the list, and may still be referenced by other threads |
214 | | * until all other threads quiesce. The replaced node ('position') may not be |
215 | | * re-inserted, re-initialized, or deleted until after all other threads have |
216 | | * quiesced (use ovsrcu_postpone). */ |
217 | | static inline void |
218 | | rculist_replace(struct rculist *element, struct rculist *position) |
219 | | OVS_NO_THREAD_SAFETY_ANALYSIS |
220 | 0 | { |
221 | 0 | struct rculist *position_next = rculist_next_protected(position); |
222 | |
|
223 | 0 | ovsrcu_set_hidden(&element->next, position_next); |
224 | 0 | position_next->prev = element; |
225 | 0 | element->prev = position->prev; |
226 | 0 | ovsrcu_set(&element->prev->next, element); |
227 | 0 | rculist_poison(position); |
228 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_replace Unexecuted instantiation: nx-match.c:rculist_replace Unexecuted instantiation: ofp-util.c:rculist_replace Unexecuted instantiation: ovs-router.c:rculist_replace Unexecuted instantiation: tnl-ports.c:rculist_replace Unexecuted instantiation: classifier.c:rculist_replace Unexecuted instantiation: conntrack.c:rculist_replace Unexecuted instantiation: conntrack-icmp.c:rculist_replace Unexecuted instantiation: conntrack-tcp.c:rculist_replace Unexecuted instantiation: conntrack-tp.c:rculist_replace Unexecuted instantiation: conntrack-other.c:rculist_replace |
229 | | |
230 | | /* Initializes 'dst' with the contents of 'src', compensating for moving it |
231 | | * around in memory. The effect is that, if 'src' was the head of a list, now |
232 | | * 'dst' is the head of a list containing the same elements. |
233 | | * |
234 | | * Memory for 'src' must be kept around until the next RCU quiescent period. |
235 | | * rculist cannot be simply reallocated, so there is no rculist_moved(). */ |
236 | | static inline void |
237 | | rculist_move(struct rculist *dst, struct rculist *src) |
238 | | OVS_NO_THREAD_SAFETY_ANALYSIS |
239 | 0 | { |
240 | 0 | if (!rculist_is_empty(src)) { |
241 | 0 | struct rculist *src_next = rculist_next_protected(src); |
242 | 0 |
|
243 | 0 | dst->prev = src->prev; |
244 | 0 | ovsrcu_set_hidden(&dst->next, src_next); |
245 | 0 |
|
246 | 0 | src_next->prev = dst; |
247 | 0 | ovsrcu_set(&src->prev->next, dst); |
248 | 0 | } else { |
249 | 0 | rculist_init(dst); |
250 | 0 | } |
251 | 0 | rculist_poison(src); |
252 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_move Unexecuted instantiation: nx-match.c:rculist_move Unexecuted instantiation: ofp-util.c:rculist_move Unexecuted instantiation: ovs-router.c:rculist_move Unexecuted instantiation: tnl-ports.c:rculist_move Unexecuted instantiation: classifier.c:rculist_move Unexecuted instantiation: conntrack.c:rculist_move Unexecuted instantiation: conntrack-icmp.c:rculist_move Unexecuted instantiation: conntrack-tcp.c:rculist_move Unexecuted instantiation: conntrack-tp.c:rculist_move Unexecuted instantiation: conntrack-other.c:rculist_move |
253 | | |
254 | | /* Removes 'elem' from its list and returns the element that followed it. |
255 | | * Has no effect when 'elem' is initialized, but not in a list. |
256 | | * Undefined behavior if 'elem' is not initialized. |
257 | | * |
258 | | * Afterward, 'elem' is not linked to from the list any more, but still links |
259 | | * to the nodes in the list, and may still be referenced by other threads until |
260 | | * all other threads quiesce. The removed node ('elem') may not be |
261 | | * re-inserted, re-initialized, or deleted until after all other threads have |
262 | | * quiesced (use ovsrcu_postpone). |
263 | | */ |
264 | | static inline struct rculist * |
265 | | rculist_remove(struct rculist *elem) |
266 | | OVS_NO_THREAD_SAFETY_ANALYSIS |
267 | 0 | { |
268 | 0 | struct rculist *elem_next = rculist_next_protected(elem); |
269 | |
|
270 | 0 | elem_next->prev = elem->prev; |
271 | 0 | ovsrcu_set(&elem->prev->next, elem_next); |
272 | 0 | rculist_poison(elem); |
273 | 0 | return elem_next; |
274 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_remove Unexecuted instantiation: nx-match.c:rculist_remove Unexecuted instantiation: ofp-util.c:rculist_remove Unexecuted instantiation: ovs-router.c:rculist_remove Unexecuted instantiation: tnl-ports.c:rculist_remove Unexecuted instantiation: classifier.c:rculist_remove Unexecuted instantiation: conntrack.c:rculist_remove Unexecuted instantiation: conntrack-icmp.c:rculist_remove Unexecuted instantiation: conntrack-tcp.c:rculist_remove Unexecuted instantiation: conntrack-tp.c:rculist_remove Unexecuted instantiation: conntrack-other.c:rculist_remove |
275 | | |
276 | | /* Removes the front element from 'list' and returns it. Undefined behavior if |
277 | | * 'list' is empty before removal. |
278 | | * |
279 | | * Afterward, teh returned former first node is not linked to from the list any |
280 | | * more, but still links to the nodes in the list, and may still be referenced |
281 | | * by other threads until all other threads quiesce. The returned node may not |
282 | | * be re-inserted, re-initialized, or deleted until after all other threads |
283 | | * have quiesced (use ovsrcu_postpone). */ |
284 | | static inline struct rculist * |
285 | | rculist_pop_front(struct rculist *list) |
286 | | OVS_NO_THREAD_SAFETY_ANALYSIS |
287 | 0 | { |
288 | 0 | struct rculist *front = rculist_next_protected(list); |
289 | 0 | rculist_remove(front); |
290 | 0 | return front; |
291 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_pop_front Unexecuted instantiation: nx-match.c:rculist_pop_front Unexecuted instantiation: ofp-util.c:rculist_pop_front Unexecuted instantiation: ovs-router.c:rculist_pop_front Unexecuted instantiation: tnl-ports.c:rculist_pop_front Unexecuted instantiation: classifier.c:rculist_pop_front Unexecuted instantiation: conntrack.c:rculist_pop_front Unexecuted instantiation: conntrack-icmp.c:rculist_pop_front Unexecuted instantiation: conntrack-tcp.c:rculist_pop_front Unexecuted instantiation: conntrack-tp.c:rculist_pop_front Unexecuted instantiation: conntrack-other.c:rculist_pop_front |
292 | | |
293 | | /* Removes the back element from 'list' and returns it. |
294 | | * Undefined behavior if 'list' is empty before removal. |
295 | | * |
296 | | * Afterward, teh returned former last node is not linked to from the list any |
297 | | * more, but still links to the nodes in the list, and may still be referenced |
298 | | * by other threads until all other threads quiesce. The returned node may not |
299 | | * be re-inserted, re-initialized, or deleted until after all other threads |
300 | | * have quiesced (use ovsrcu_postpone). */ |
301 | | static inline struct rculist * |
302 | | rculist_pop_back(struct rculist *list) |
303 | | OVS_NO_THREAD_SAFETY_ANALYSIS |
304 | 0 | { |
305 | 0 | struct rculist *back = list->prev; |
306 | 0 | rculist_remove(back); |
307 | 0 | return back; |
308 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_pop_back Unexecuted instantiation: nx-match.c:rculist_pop_back Unexecuted instantiation: ofp-util.c:rculist_pop_back Unexecuted instantiation: ovs-router.c:rculist_pop_back Unexecuted instantiation: tnl-ports.c:rculist_pop_back Unexecuted instantiation: classifier.c:rculist_pop_back Unexecuted instantiation: conntrack.c:rculist_pop_back Unexecuted instantiation: conntrack-icmp.c:rculist_pop_back Unexecuted instantiation: conntrack-tcp.c:rculist_pop_back Unexecuted instantiation: conntrack-tp.c:rculist_pop_back Unexecuted instantiation: conntrack-other.c:rculist_pop_back |
309 | | |
310 | | /* Returns the front element in 'list_'. |
311 | | * Undefined behavior if 'list_' is empty. */ |
312 | | static inline const struct rculist * |
313 | | rculist_front(const struct rculist *list) |
314 | 0 | { |
315 | 0 | ovs_assert(!rculist_is_empty(list)); |
316 | 0 |
|
317 | 0 | return rculist_next(list); |
318 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_front Unexecuted instantiation: nx-match.c:rculist_front Unexecuted instantiation: ofp-util.c:rculist_front Unexecuted instantiation: ovs-router.c:rculist_front Unexecuted instantiation: tnl-ports.c:rculist_front Unexecuted instantiation: classifier.c:rculist_front Unexecuted instantiation: conntrack.c:rculist_front Unexecuted instantiation: conntrack-icmp.c:rculist_front Unexecuted instantiation: conntrack-tcp.c:rculist_front Unexecuted instantiation: conntrack-tp.c:rculist_front Unexecuted instantiation: conntrack-other.c:rculist_front |
319 | | |
320 | | /* Returns the back element in 'list_'. |
321 | | * Returns the 'list_' itself, if 'list_' is empty. */ |
322 | | static inline struct rculist * |
323 | | rculist_back_protected(const struct rculist *list) |
324 | | OVS_NO_THREAD_SAFETY_ANALYSIS |
325 | 0 | { |
326 | 0 | return CONST_CAST(struct rculist *, list)->prev; |
327 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_back_protected Unexecuted instantiation: nx-match.c:rculist_back_protected Unexecuted instantiation: ofp-util.c:rculist_back_protected Unexecuted instantiation: ovs-router.c:rculist_back_protected Unexecuted instantiation: tnl-ports.c:rculist_back_protected Unexecuted instantiation: classifier.c:rculist_back_protected Unexecuted instantiation: conntrack.c:rculist_back_protected Unexecuted instantiation: conntrack-icmp.c:rculist_back_protected Unexecuted instantiation: conntrack-tcp.c:rculist_back_protected Unexecuted instantiation: conntrack-tp.c:rculist_back_protected Unexecuted instantiation: conntrack-other.c:rculist_back_protected |
328 | | |
329 | | /* Returns the number of elements in 'list'. |
330 | | * Runs in O(n) in the number of elements. */ |
331 | | static inline size_t |
332 | | rculist_size(const struct rculist *list) |
333 | 0 | { |
334 | 0 | const struct rculist *e; |
335 | 0 | size_t cnt = 0; |
336 | 0 |
|
337 | 0 | for (e = rculist_next(list); e != list; e = rculist_next(e)) { |
338 | 0 | cnt++; |
339 | 0 | } |
340 | 0 | return cnt; |
341 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_size Unexecuted instantiation: nx-match.c:rculist_size Unexecuted instantiation: ofp-util.c:rculist_size Unexecuted instantiation: ovs-router.c:rculist_size Unexecuted instantiation: tnl-ports.c:rculist_size Unexecuted instantiation: classifier.c:rculist_size Unexecuted instantiation: conntrack.c:rculist_size Unexecuted instantiation: conntrack-icmp.c:rculist_size Unexecuted instantiation: conntrack-tcp.c:rculist_size Unexecuted instantiation: conntrack-tp.c:rculist_size Unexecuted instantiation: conntrack-other.c:rculist_size |
342 | | |
343 | | /* Returns true if 'list' is empty, false otherwise. */ |
344 | | static inline bool |
345 | | rculist_is_empty(const struct rculist *list) |
346 | 0 | { |
347 | 0 | return rculist_next(list) == list; |
348 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_is_empty Unexecuted instantiation: nx-match.c:rculist_is_empty Unexecuted instantiation: ofp-util.c:rculist_is_empty Unexecuted instantiation: ovs-router.c:rculist_is_empty Unexecuted instantiation: tnl-ports.c:rculist_is_empty Unexecuted instantiation: classifier.c:rculist_is_empty Unexecuted instantiation: conntrack.c:rculist_is_empty Unexecuted instantiation: conntrack-icmp.c:rculist_is_empty Unexecuted instantiation: conntrack-tcp.c:rculist_is_empty Unexecuted instantiation: conntrack-tp.c:rculist_is_empty Unexecuted instantiation: conntrack-other.c:rculist_is_empty |
349 | | |
350 | | /* Returns true if 'list' has 0 or 1 elements, false otherwise. */ |
351 | | static inline bool |
352 | | rculist_is_short_protected(const struct rculist *list) |
353 | | OVS_NO_THREAD_SAFETY_ANALYSIS |
354 | 0 | { |
355 | 0 | return rculist_next_protected(list) == list->prev; |
356 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_is_short_protected Unexecuted instantiation: nx-match.c:rculist_is_short_protected Unexecuted instantiation: ofp-util.c:rculist_is_short_protected Unexecuted instantiation: ovs-router.c:rculist_is_short_protected Unexecuted instantiation: tnl-ports.c:rculist_is_short_protected Unexecuted instantiation: classifier.c:rculist_is_short_protected Unexecuted instantiation: conntrack.c:rculist_is_short_protected Unexecuted instantiation: conntrack-icmp.c:rculist_is_short_protected Unexecuted instantiation: conntrack-tcp.c:rculist_is_short_protected Unexecuted instantiation: conntrack-tp.c:rculist_is_short_protected Unexecuted instantiation: conntrack-other.c:rculist_is_short_protected |
357 | | |
358 | | /* Returns true if 'list' has exactly 1 element, false otherwise. */ |
359 | | static inline bool |
360 | | rculist_is_singleton_protected(const struct rculist *list) |
361 | | OVS_NO_THREAD_SAFETY_ANALYSIS |
362 | 0 | { |
363 | 0 | const struct rculist *list_next = rculist_next_protected(list); |
364 | 0 |
|
365 | 0 | return list_next == list->prev && list_next != list; |
366 | 0 | } Unexecuted instantiation: meta-flow.c:rculist_is_singleton_protected Unexecuted instantiation: nx-match.c:rculist_is_singleton_protected Unexecuted instantiation: ofp-util.c:rculist_is_singleton_protected Unexecuted instantiation: ovs-router.c:rculist_is_singleton_protected Unexecuted instantiation: tnl-ports.c:rculist_is_singleton_protected Unexecuted instantiation: classifier.c:rculist_is_singleton_protected Unexecuted instantiation: conntrack.c:rculist_is_singleton_protected Unexecuted instantiation: conntrack-icmp.c:rculist_is_singleton_protected Unexecuted instantiation: conntrack-tcp.c:rculist_is_singleton_protected Unexecuted instantiation: conntrack-tp.c:rculist_is_singleton_protected Unexecuted instantiation: conntrack-other.c:rculist_is_singleton_protected |
367 | | |
368 | | #define RCULIST_FOR_EACH(ITER, MEMBER, RCULIST) \ |
369 | 0 | for (INIT_MULTIVAR(ITER, MEMBER, rculist_next(RCULIST), \ |
370 | 0 | const struct rculist); \ |
371 | 0 | CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST)); \ |
372 | 0 | UPDATE_MULTIVAR(ITER, rculist_next(ITER_VAR(ITER)))) |
373 | | |
374 | | #define RCULIST_FOR_EACH_CONTINUE(ITER, MEMBER, RCULIST) \ |
375 | 0 | for (INIT_MULTIVAR(ITER, MEMBER, rculist_next(&(ITER)->MEMBER), \ |
376 | 0 | const struct rculist); \ |
377 | 0 | CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST)); \ |
378 | 0 | UPDATE_MULTIVAR(ITER, rculist_next(ITER_VAR(ITER)))) |
379 | | |
380 | | #define RCULIST_FOR_EACH_REVERSE_PROTECTED(ITER, MEMBER, RCULIST) \ |
381 | | for (INIT_MULTIVAR(ITER, MEMBER, rculist_back_protected(RCULIST), \ |
382 | | struct rculist); \ |
383 | | CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST)); \ |
384 | | UPDATE_MULTIVAR(ITER, rculist_back_protected(ITER_VAR(ITER)))) |
385 | | |
386 | | #define RCULIST_FOR_EACH_REVERSE_PROTECTED_CONTINUE(ITER, MEMBER, RCULIST) \ |
387 | | for (INIT_MULTIVAR(ITER, MEMBER, rculist_back_protected(ITER->MEMBER), \ |
388 | | struct rculist); \ |
389 | | CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST)); \ |
390 | | UPDATE_MULTIVAR(ITER, ITER_VAR(ITER)->prev)) |
391 | | |
392 | | #define RCULIST_FOR_EACH_PROTECTED(ITER, MEMBER, RCULIST) \ |
393 | | for (INIT_MULTIVAR(ITER, MEMBER, rculist_next_protected(RCULIST), \ |
394 | | struct rculist); \ |
395 | | CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST)); \ |
396 | | UPDATE_MULTIVAR(ITER, rculist_next_protected(ITER_VAR(ITER)))) \ |
397 | | |
398 | | #define RCULIST_FOR_EACH_SAFE_SHORT_PROTECTED(ITER, MEMBER, RCULIST) \ |
399 | | for (INIT_MULTIVAR_SAFE_SHORT(ITER, MEMBER, \ |
400 | | rculist_next_protected(RCULIST), \ |
401 | | struct rculist); \ |
402 | | CONDITION_MULTIVAR_SAFE_SHORT(ITER, MEMBER, \ |
403 | | ITER_VAR(ITER) != (RCULIST), \ |
404 | | ITER_NEXT_VAR(ITER) = rculist_next_protected(ITER_VAR(ITER))); \ |
405 | | UPDATE_MULTIVAR_SAFE_SHORT(ITER)) |
406 | | |
407 | | #define RCULIST_FOR_EACH_SAFE_LONG_PROTECTED(ITER, NEXT, MEMBER, RCULIST) \ |
408 | | for (INIT_MULTIVAR_SAFE_LONG(ITER, NEXT, MEMBER, \ |
409 | | rculist_next_protected(RCULIST), \ |
410 | | struct rculist); \ |
411 | | CONDITION_MULTIVAR_SAFE_LONG(ITER, NEXT, MEMBER, \ |
412 | | ITER_VAR(ITER) != (RCULIST), \ |
413 | | ITER_VAR(NEXT) = rculist_next_protected(ITER_VAR(ITER)), \ |
414 | | ITER_VAR(NEXT) != (RCULIST)); \ |
415 | | UPDATE_MULTIVAR_SAFE_LONG(ITER, NEXT)) |
416 | | |
417 | | #define RCULIST_FOR_EACH_SAFE_PROTECTED(...) \ |
418 | | OVERLOAD_SAFE_MACRO(RCULIST_FOR_EACH_SAFE_LONG_PROTECTED, \ |
419 | | RCULIST_FOR_EACH_SAFE_SHORT_PROTECTED, \ |
420 | | 4, __VA_ARGS__) |
421 | | |
422 | | |
423 | | #endif /* rculist.h */ |