1 /*
2  * include/common/mini-clist.h
3  * Circular list manipulation macros and structures.
4  *
5  * Copyright (C) 2002-2014 Willy Tarreau - w@1wt.eu
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation, version 2.1
10  * exclusively.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #ifndef _COMMON_MINI_CLIST_H
23 #define _COMMON_MINI_CLIST_H
24 
25 #include <common/config.h>
26 
27 /* these are circular or bidirectionnal lists only. Each list pointer points to
28  * another list pointer in a structure, and not the structure itself. The
29  * pointer to the next element MUST be the first one so that the list is easily
30  * cast as a single linked list or pointer.
31  */
32 struct list {
33     struct list *n;	/* next */
34     struct list *p;	/* prev */
35 };
36 
37 /* This is similar to struct list, but we want to be sure the compiler will
38  * yell at you if you use macroes for one when you're using the other. You have
39  * to expicitely cast if that's really what you want to do.
40  */
41 struct mt_list {
42     struct mt_list *next;
43     struct mt_list *prev;
44 };
45 
46 
47 /* a back-ref is a pointer to a target list entry. It is used to detect when an
48  * element being deleted is currently being tracked by another user. The best
49  * example is a user dumping the session table. The table does not fit in the
50  * output buffer so we have to set a mark on a session and go on later. But if
51  * that marked session gets deleted, we don't want the user's pointer to go in
52  * the wild. So we can simply link this user's request to the list of this
53  * session's users, and put a pointer to the list element in ref, that will be
54  * used as the mark for next iteration.
55  */
56 struct bref {
57 	struct list users;
58 	struct list *ref; /* pointer to the target's list entry */
59 };
60 
61 /* a word list is a generic list with a pointer to a string in each element. */
62 struct wordlist {
63 	struct list list;
64 	char *s;
65 };
66 
67 /* this is the same as above with an additional pointer to a condition. */
68 struct cond_wordlist {
69 	struct list list;
70 	void *cond;
71 	char *s;
72 };
73 
74 /* First undefine some macros which happen to also be defined on OpenBSD,
75  * in sys/queue.h, used by sys/event.h
76  */
77 #undef LIST_HEAD
78 #undef LIST_INIT
79 #undef LIST_NEXT
80 
81 /* ILH = Initialized List Head : used to prevent gcc from moving an empty
82  * list to BSS. Some older version tend to trim all the array and cause
83  * corruption.
84  */
85 #define ILH		{ .n = (struct list *)1, .p = (struct list *)2 }
86 
87 #define LIST_HEAD(a)	((void *)(&(a)))
88 
89 #define LIST_INIT(l) ((l)->n = (l)->p = (l))
90 
91 #define LIST_HEAD_INIT(l) { &l, &l }
92 
93 /* adds an element at the beginning of a list ; returns the element */
94 #define LIST_ADD(lh, el) ({ (el)->n = (lh)->n; (el)->n->p = (lh)->n = (el); (el)->p = (lh); (el); })
95 
96 /* adds an element at the end of a list ; returns the element */
97 #define LIST_ADDQ(lh, el) ({ (el)->p = (lh)->p; (el)->p->n = (lh)->p = (el); (el)->n = (lh); (el); })
98 
99 /* adds the contents of a list <old> at the beginning of another list <new>. The old list head remains untouched. */
100 #define LIST_SPLICE(new, old) do {				     \
101 		if (!LIST_ISEMPTY(old)) {			     \
102 			(old)->p->n = (new)->n; (old)->n->p = (new); \
103 			(new)->n->p = (old)->p; (new)->n = (old)->n; \
104 		}						     \
105 	} while (0)
106 
107 /* adds the contents of a list whose first element is <old> and last one is
108  * <old->prev> at the end of another list <new>. The old list DOES NOT have
109  * any head here.
110  */
111 #define LIST_SPLICE_END_DETACHED(new, old) do {              \
112 		typeof(new) __t;                             \
113 		(new)->p->n = (old);                         \
114 		(old)->p->n = (new);                         \
115 		__t = (old)->p;                              \
116 		(old)->p = (new)->p;                         \
117 		(new)->p = __t;                              \
118 	} while (0)
119 
120 /* removes an element from a list and returns it */
121 #define LIST_DEL(el) ({ typeof(el) __ret = (el); (el)->n->p = (el)->p; (el)->p->n = (el)->n; (__ret); })
122 
123 /* removes an element from a list, initializes it and returns it.
124  * This is faster than LIST_DEL+LIST_INIT as we avoid reloading the pointers.
125  */
126 #define LIST_DEL_INIT(el) ({ \
127 	typeof(el) __ret = (el);                        \
128 	typeof(__ret->n) __n = __ret->n;                \
129 	typeof(__ret->p) __p = __ret->p;                \
130 	__n->p = __p; __p->n = __n;                     \
131 	__ret->n = __ret->p = __ret;                    \
132 	__ret;                                          \
133 })
134 
135 /* returns a pointer of type <pt> to a structure containing a list head called
136  * <el> at address <lh>. Note that <lh> can be the result of a function or macro
137  * since it's used only once.
138  * Example: LIST_ELEM(cur_node->args.next, struct node *, args)
139  */
140 #define LIST_ELEM(lh, pt, el) ((pt)(((const char *)(lh)) - ((size_t)&((pt)NULL)->el)))
141 
142 /* checks if the list head <lh> is empty or not */
143 #define LIST_ISEMPTY(lh) ((lh)->n == (lh))
144 
145 /* checks if the list element <el> was added to a list or not. This only
146  * works when detached elements are reinitialized (using LIST_DEL_INIT)
147  */
148 #define LIST_ADDED(el) ((el)->n != (el))
149 
150 /* returns a pointer of type <pt> to a structure following the element
151  * which contains list head <lh>, which is known as element <el> in
152  * struct pt.
153  * Example: LIST_NEXT(args, struct node *, list)
154  */
155 #define LIST_NEXT(lh, pt, el) (LIST_ELEM((lh)->n, pt, el))
156 
157 
158 /* returns a pointer of type <pt> to a structure preceding the element
159  * which contains list head <lh>, which is known as element <el> in
160  * struct pt.
161  */
162 #undef LIST_PREV
163 #define LIST_PREV(lh, pt, el) (LIST_ELEM((lh)->p, pt, el))
164 
165 /*
166  * Simpler FOREACH_ITEM macro inspired from Linux sources.
167  * Iterates <item> through a list of items of type "typeof(*item)" which are
168  * linked via a "struct list" member named <member>. A pointer to the head of
169  * the list is passed in <list_head>. No temporary variable is needed. Note
170  * that <item> must not be modified during the loop.
171  * Example: list_for_each_entry(cur_acl, known_acl, list) { ... };
172  */
173 #define list_for_each_entry(item, list_head, member)                      \
174 	for (item = LIST_ELEM((list_head)->n, typeof(item), member);     \
175 	     &item->member != (list_head);                                \
176 	     item = LIST_ELEM(item->member.n, typeof(item), member))
177 
178 /*
179  * Same as list_for_each_entry but starting from current point
180  * Iterates <item> through the list starting from <item>
181  * It's basically the same macro but without initializing item to the head of
182  * the list.
183  */
184 #define list_for_each_entry_from(item, list_head, member) \
185 	for ( ; &item->member != (list_head); \
186 	     item = LIST_ELEM(item->member.n, typeof(item), member))
187 
188 /*
189  * Simpler FOREACH_ITEM_SAFE macro inspired from Linux sources.
190  * Iterates <item> through a list of items of type "typeof(*item)" which are
191  * linked via a "struct list" member named <member>. A pointer to the head of
192  * the list is passed in <list_head>. A temporary variable <back> of same type
193  * as <item> is needed so that <item> may safely be deleted if needed.
194  * Example: list_for_each_entry_safe(cur_acl, tmp, known_acl, list) { ... };
195  */
196 #define list_for_each_entry_safe(item, back, list_head, member)           \
197 	for (item = LIST_ELEM((list_head)->n, typeof(item), member),     \
198 	     back = LIST_ELEM(item->member.n, typeof(item), member);     \
199 	     &item->member != (list_head);                                \
200 	     item = back, back = LIST_ELEM(back->member.n, typeof(back), member))
201 
202 
203 /*
204  * Same as list_for_each_entry_safe but starting from current point
205  * Iterates <item> through the list starting from <item>
206  * It's basically the same macro but without initializing item to the head of
207  * the list.
208  */
209 #define list_for_each_entry_safe_from(item, back, list_head, member) \
210 	for (back = LIST_ELEM(item->member.n, typeof(item), member);     \
211 	     &item->member != (list_head);                                \
212 	     item = back, back = LIST_ELEM(back->member.n, typeof(back), member))
213 
214 #include <common/hathreads.h>
215 #define MT_LIST_BUSY ((struct mt_list *)1)
216 
217 /*
218  * Locked version of list manipulation macros.
219  * It is OK to use those concurrently from multiple threads, as long as the
220  * list is only used with the locked variants.
221  */
222 
223 /*
224  * Add an item at the beginning of a list.
225  * Returns 1 if we added the item, 0 otherwise (because it was already in a
226  * list).
227  */
228 #define MT_LIST_ADD(_lh, _el)                                              \
229      ({                                                                    \
230         int _ret = 0;                                                      \
231 	struct mt_list *lh = (_lh), *el = (_el);                           \
232 	do {                                                               \
233 		while (1) {                                                \
234 			struct mt_list *n;                                 \
235 			struct mt_list *p;                                 \
236 			n = _HA_ATOMIC_XCHG(&(lh)->next, MT_LIST_BUSY);    \
237 			if (n == MT_LIST_BUSY)                             \
238 			        continue;                                  \
239 			p = _HA_ATOMIC_XCHG(&n->prev, MT_LIST_BUSY);       \
240 			if (p == MT_LIST_BUSY) {                           \
241 				(lh)->next = n;                            \
242 				__ha_barrier_store();                      \
243 				continue;                                  \
244 			}                                                  \
245 			if ((el)->next != (el) || (el)->prev != (el)) {    \
246 				(n)->prev = p;                             \
247 				(lh)->next = n;                            \
248 				break;                                     \
249 			}                                                  \
250 			(el)->next = n;                                    \
251 			(el)->prev = p;                                    \
252 			__ha_barrier_store();                              \
253 			n->prev = (el);                                    \
254 			__ha_barrier_store();                              \
255 			p->next = (el);                                    \
256 			__ha_barrier_store();                              \
257 			_ret = 1;                                          \
258 			break;                                             \
259 		}                                                          \
260 	} while (0);                                                       \
261 	(_ret);                                                            \
262      })
263 
264 /*
265  * Add an item at the end of a list.
266  * Returns 1 if we added the item, 0 otherwise (because it was already in a
267  * list).
268  */
269 #define MT_LIST_ADDQ(_lh, _el)                                             \
270     ({                                                                     \
271 	    int _ret = 0;                                                  \
272 	    struct mt_list *lh = (_lh), *el = (_el);                       \
273 	do {                                                               \
274 		while (1) {                                                \
275 			struct mt_list *n;                                 \
276 			struct mt_list *p;                                 \
277 			p = _HA_ATOMIC_XCHG(&(lh)->prev, MT_LIST_BUSY);    \
278 			if (p == MT_LIST_BUSY)                             \
279 			        continue;                                  \
280 			n = _HA_ATOMIC_XCHG(&p->next, MT_LIST_BUSY);       \
281 			if (n == MT_LIST_BUSY) {                           \
282 				(lh)->prev = p;                            \
283 				__ha_barrier_store();                      \
284 				continue;                                  \
285 			}                                                  \
286 			if ((el)->next != (el) || (el)->prev != (el)) {    \
287 				p->next = n;                               \
288 				(lh)->prev = p;                            \
289 				break;                                     \
290 			}                                                  \
291 			(el)->next = n;                                    \
292 			(el)->prev = p;                                    \
293 			__ha_barrier_store();                              \
294 			p->next = (el);                                    \
295 			__ha_barrier_store();                              \
296 			n->prev = (el);                                    \
297 			__ha_barrier_store();                              \
298 			_ret = 1;                                          \
299 			break;                                             \
300 		}                                                          \
301 	} while (0);                                                       \
302 	(_ret);                                                            \
303     })
304 
305 /*
306  * Detach a list from its head. A pointer to the first element is returned
307  * and the list is closed. If the list was empty, NULL is returned. This may
308  * exclusively be used with lists modified by MT_LIST_ADD/MT_LIST_ADDQ. This
309  * is incompatible with MT_LIST_DEL run concurrently.
310  * If there's at least one element, the next of the last element will always
311  * be NULL.
312  */
313 #define MT_LIST_BEHEAD(_lh) ({                                      \
314         struct mt_list *lh = (_lh);                                 \
315 	struct mt_list *_n;                                         \
316 	struct mt_list *_p;                                         \
317 	while (1) {                                                 \
318 		_p = _HA_ATOMIC_XCHG(&(lh)->prev, MT_LIST_BUSY);    \
319 		if (_p == MT_LIST_BUSY)                             \
320 		        continue;                                   \
321 		if (_p == (lh)) {                                   \
322 			(lh)->prev = _p;                            \
323 			_n = NULL;                                  \
324 			break;                                      \
325 		}                                                   \
326 		_n = _HA_ATOMIC_XCHG(&(lh)->next, MT_LIST_BUSY);    \
327 		if (_n == MT_LIST_BUSY) {                           \
328 			(lh)->prev = _p;                            \
329 			__ha_barrier_store();                       \
330 			continue;                                   \
331 		}                                                   \
332 		if (_n == (lh)) {                                   \
333 			(lh)->next = _n;                            \
334 			(lh)->prev = _p;                            \
335 			_n = NULL;                                  \
336 			break;                                      \
337 		}                                                   \
338 		(lh)->next = (lh);                                  \
339 		(lh)->prev = (lh);                                  \
340 		_n->prev = _p;                                      \
341 		_p->next = NULL;                                    \
342 		__ha_barrier_store();                               \
343 		break;                                              \
344 	}                                                           \
345 	(_n);                                                       \
346 })
347 
348 
349 /* Remove an item from a list.
350  * Returns 1 if we removed the item, 0 otherwise (because it was in no list).
351  */
352 #define MT_LIST_DEL(_el)                                                   \
353     ({                                                                     \
354         int _ret = 0;                                                      \
355 	struct mt_list *el = (_el);                                        \
356 	do {                                                               \
357 		while (1) {                                                \
358 			struct mt_list *n, *n2;                            \
359 			struct mt_list *p, *p2 = NULL;                     \
360 			n = _HA_ATOMIC_XCHG(&(el)->next, MT_LIST_BUSY);    \
361 			if (n == MT_LIST_BUSY)                             \
362 			        continue;                                  \
363 			p = _HA_ATOMIC_XCHG(&(el)->prev, MT_LIST_BUSY);    \
364 			if (p == MT_LIST_BUSY) {                           \
365 				(el)->next = n;                            \
366 				__ha_barrier_store();                      \
367 				continue;                                  \
368 			}                                                  \
369 			if (p != (el)) {                                   \
370 			        p2 = _HA_ATOMIC_XCHG(&p->next, MT_LIST_BUSY);\
371 			        if (p2 == MT_LIST_BUSY) {                  \
372 			                (el)->prev = p;                    \
373 					(el)->next = n;                    \
374 					__ha_barrier_store();              \
375 					continue;                          \
376 				}                                          \
377 			}                                                  \
378 			if (n != (el)) {                                   \
379 			        n2 = _HA_ATOMIC_XCHG(&n->prev, MT_LIST_BUSY);\
380 				if (n2 == MT_LIST_BUSY) {                  \
381 					if (p2 != NULL)                    \
382 						p->next = p2;              \
383 					(el)->prev = p;                    \
384 					(el)->next = n;                    \
385 					__ha_barrier_store();              \
386 					continue;                          \
387 				}                                          \
388 			}                                                  \
389 			n->prev = p;                                       \
390 			p->next = n;                                       \
391 			if (p != (el) && n != (el))                        \
392 				_ret = 1;                                  \
393 			__ha_barrier_store();                              \
394 			(el)->prev = (el);                                 \
395 			(el)->next = (el);                                 \
396 			__ha_barrier_store();                              \
397 			break;                                             \
398 		}                                                          \
399 	} while (0);                                                       \
400 	(_ret);                                                            \
401     })
402 
403 
404 /* Remove the first element from the list, and return it */
405 #define MT_LIST_POP(_lh, pt, el)                                           \
406 	({                                                                 \
407 		 void *_ret;                                               \
408 		 struct mt_list *lh = (_lh);                               \
409 		 while (1) {                                               \
410 			 struct mt_list *n, *n2;                           \
411 			 struct mt_list *p, *p2;                           \
412 			 n = _HA_ATOMIC_XCHG(&(lh)->next, MT_LIST_BUSY);   \
413 			 if (n == MT_LIST_BUSY)                            \
414 			         continue;                                 \
415 			 if (n == (lh)) {                                  \
416 				 (lh)->next = lh;                          \
417 				 __ha_barrier_store();                     \
418 				 _ret = NULL;                              \
419 				 break;                                    \
420 			 }                                                 \
421 			 p = _HA_ATOMIC_XCHG(&n->prev, MT_LIST_BUSY);      \
422 			 if (p == MT_LIST_BUSY) {                          \
423 				 (lh)->next = n;                           \
424 				 __ha_barrier_store();                     \
425 				 continue;                                 \
426 			 }                                                 \
427 			 n2 = _HA_ATOMIC_XCHG(&n->next, MT_LIST_BUSY);     \
428 			 if (n2 == MT_LIST_BUSY) {                         \
429 				 n->prev = p;                              \
430 				 __ha_barrier_store();                     \
431 				 (lh)->next = n;                           \
432 				 __ha_barrier_store();                     \
433 				 continue;                                 \
434 			 }                                                 \
435 			 p2 = _HA_ATOMIC_XCHG(&n2->prev, MT_LIST_BUSY);    \
436 			 if (p2 == MT_LIST_BUSY) {                         \
437 				 n->next = n2;                             \
438 				 n->prev = p;                              \
439 				 __ha_barrier_store();                     \
440 				 (lh)->next = n;                           \
441 				 __ha_barrier_store();                     \
442 				 continue;                                 \
443 			 }                                                 \
444 			 (lh)->next = n2;                                  \
445 			 (n2)->prev = (lh);                                \
446 			 __ha_barrier_store();                             \
447 			 (n)->prev = (n);                                  \
448 			 (n)->next = (n);	                           \
449 			 __ha_barrier_store();                             \
450 			 _ret = MT_LIST_ELEM(n, pt, el);                   \
451 			 break;                                            \
452 		 }                                                         \
453 		 (_ret);                                                   \
454 	 })
455 
456 #define MT_LIST_HEAD(a)	((void *)(&(a)))
457 
458 #define MT_LIST_INIT(l) ((l)->next = (l)->prev = (l))
459 
460 #define MT_LIST_HEAD_INIT(l) { &l, &l }
461 /* returns a pointer of type <pt> to a structure containing a list head called
462  * <el> at address <lh>. Note that <lh> can be the result of a function or macro
463  * since it's used only once.
464  * Example: MT_LIST_ELEM(cur_node->args.next, struct node *, args)
465  */
466 #define MT_LIST_ELEM(lh, pt, el) ((pt)(((const char *)(lh)) - ((size_t)&((pt)NULL)->el)))
467 
468 /* checks if the list head <lh> is empty or not */
469 #define MT_LIST_ISEMPTY(lh) ((lh)->next == (lh))
470 
471 /* returns a pointer of type <pt> to a structure following the element
472  * which contains list head <lh>, which is known as element <el> in
473  * struct pt.
474  * Example: MT_LIST_NEXT(args, struct node *, list)
475  */
476 #define MT_LIST_NEXT(lh, pt, el) (MT_LIST_ELEM((lh)->next, pt, el))
477 
478 
479 /* returns a pointer of type <pt> to a structure preceding the element
480  * which contains list head <lh>, which is known as element <el> in
481  * struct pt.
482  */
483 #undef MT_LIST_PREV
484 #define MT_LIST_PREV(lh, pt, el) (MT_LIST_ELEM((lh)->prev, pt, el))
485 
486 /* checks if the list element <el> was added to a list or not. This only
487  * works when detached elements are reinitialized (using LIST_DEL_INIT)
488  */
489 #define MT_LIST_ADDED(el) ((el)->next != (el))
490 
491 /* Lock an element in the list, to be sure it won't be removed.
492  * It needs to be synchronized somehow to be sure it's not removed
493  * from the list in the meanwhile.
494  * This returns a struct mt_list, that will be needed at unlock time.
495  */
496 #define MT_LIST_LOCK_ELT(_el)                                              \
497 	({                                                                 \
498 		struct mt_list ret;                                        \
499 		struct mt_liet *el = (_el);                                \
500 		while (1) {                                                \
501 			struct mt_list *n, *n2;                            \
502 			struct mt_list *p, *p2 = NULL;                     \
503 			n = _HA_ATOMIC_XCHG(&(el)->next, MT_LIST_BUSY);    \
504 			if (n == MT_LIST_BUSY)                             \
505 			        continue;                                  \
506 			p = _HA_ATOMIC_XCHG(&(el)->prev, MT_LIST_BUSY);    \
507 			if (p == MT_LIST_BUSY) {                           \
508 				(el)->next = n;                            \
509 				__ha_barrier_store();                      \
510 				continue;                                  \
511 			}                                                  \
512 			if (p != (el)) {                                   \
513 			        p2 = _HA_ATOMIC_XCHG(&p->next, MT_LIST_BUSY);\
514 			        if (p2 == MT_LIST_BUSY) {                  \
515 			                (el)->prev = p;                    \
516 					(el)->next = n;                    \
517 					__ha_barrier_store();              \
518 					continue;                          \
519 				}                                          \
520 			}                                                  \
521 			if (n != (el)) {                                   \
522 			        n2 = _HA_ATOMIC_XCHG(&n->prev, MT_LIST_BUSY);\
523 				if (n2 == MT_LIST_BUSY) {                  \
524 					if (p2 != NULL)                    \
525 						p->next = p2;              \
526 					(el)->prev = p;                    \
527 					(el)->next = n;                    \
528 					__ha_barrier_store();              \
529 					continue;                          \
530 				}                                          \
531 			}                                                  \
532 			ret.next = n;                                      \
533 			ret.prev = p;                                      \
534 			break;                                             \
535 		}                                                          \
536 		ret;                                                       \
537 	})
538 
539 /* Unlock an element previously locked by MT_LIST_LOCK_ELT. "np" is the
540  * struct mt_list returned by MT_LIST_LOCK_ELT().
541  */
542 #define MT_LIST_UNLOCK_ELT(_el, np)                                        \
543 	do {                                                               \
544 		struct mt_list *n = (np).next, *p = (np).prev;             \
545 		struct mt_list *el = (_el);                                \
546 		(el)->next = n;                                            \
547 		(el)->prev = p;                                            \
548 		if (n != (el))                                             \
549 			n->prev = (el);                                    \
550 		if (p != (el))                                             \
551 			p->next = (el);                                    \
552 	} while (0)
553 
554 /* Internal macroes for the foreach macroes */
555 #define _MT_LIST_UNLOCK_NEXT(el, np)                                       \
556 	do {                                                               \
557 		struct mt_list *n = (np);                                  \
558 		(el)->next = n;                                            \
559 		if (n != (el))                                             \
560 		        n->prev = (el);                                    \
561 	} while (0)
562 
563 /* Internal macroes for the foreach macroes */
564 #define _MT_LIST_UNLOCK_PREV(el, np)                                       \
565 	do {                                                               \
566 		struct mt_list *p = (np);                                  \
567 		(el)->prev = p;                                            \
568 		if (p != (el))                                             \
569 		        p->next = (el);                                    \
570 	} while (0)
571 
572 #define _MT_LIST_LOCK_NEXT(el)                                             \
573 	({                                                                 \
574 	        struct mt_list *n = NULL;                                  \
575 		while (1) {                                                \
576 			struct mt_list *n2;                                \
577 			n = _HA_ATOMIC_XCHG(&((el)->next), MT_LIST_BUSY);  \
578 			if (n == MT_LIST_BUSY)                             \
579 			        continue;                                  \
580 			if (n != (el)) {                                   \
581 			        n2 = _HA_ATOMIC_XCHG(&n->prev, MT_LIST_BUSY);\
582 				if (n2 == MT_LIST_BUSY) {                  \
583 					(el)->next = n;                    \
584 					__ha_barrier_store();              \
585 					continue;                          \
586 				}                                          \
587 			}                                                  \
588 			break;                                             \
589 		}                                                          \
590 		n;                                                         \
591 	})
592 
593 #define _MT_LIST_LOCK_PREV(el)                                             \
594 	({                                                                 \
595 	        struct mt_list *p = NULL;                                  \
596 		while (1) {                                                \
597 			struct mt_list *p2;                                \
598 			p = _HA_ATOMIC_XCHG(&((el)->prev), MT_LIST_BUSY);  \
599 			if (p == MT_LIST_BUSY)                             \
600 			        continue;                                  \
601 			if (p != (el)) {                                   \
602 			        p2 = _HA_ATOMIC_XCHG(&p->next, MT_LIST_BUSY);\
603 				if (p2 == MT_LIST_BUSY) {                  \
604 					(el)->prev = p;                    \
605 					__ha_barrier_store();              \
606 					continue;                          \
607 				}                                          \
608 			}                                                  \
609 			break;                                             \
610 		}                                                          \
611 		p;                                                         \
612 	})
613 
614 #define _MT_LIST_RELINK_DELETED(elt2)                                      \
615     do {                                                                   \
616 	    struct mt_list *n = elt2.next, *p = elt2.prev;                 \
617 	    ALREADY_CHECKED(p);                                            \
618 	    n->prev = p;                                                   \
619 	    p->next = n;                                                   \
620     } while (0);
621 
622 /* Equivalent of MT_LIST_DEL(), to be used when parsing the list with mt_list_entry_for_each_safe().
623  * It should be the element currently parsed (tmpelt1)
624  */
625 #define MT_LIST_DEL_SAFE(_el)                                              \
626 	do {                                                               \
627 		struct mt_list *el = (_el);                                \
628 		(el)->prev = (el);                                         \
629 		(el)->next = (el);                                         \
630 		(_el) = NULL;                                              \
631 	} while (0)
632 
633 /* Simpler FOREACH_ITEM_SAFE macro inspired from Linux sources.
634  * Iterates <item> through a list of items of type "typeof(*item)" which are
635  * linked via a "struct list" member named <member>. A pointer to the head of
636  * the list is passed in <list_head>. A temporary variable <back> of same type
637  * as <item> is needed so that <item> may safely be deleted if needed.
638  * tmpelt1 is a temporary struct mt_list *, and tmpelt2 is a temporary
639  * struct mt_list, used internally, both are needed for MT_LIST_DEL_SAFE.
640  * Example: list_for_each_entry_safe(cur_acl, tmp, known_acl, list, elt1, elt2)
641  * { ... };
642  * If you want to remove the current element, please use MT_LIST_DEL_SAFE.
643  */
644 #define mt_list_for_each_entry_safe(item, list_head, member, tmpelt, tmpelt2)           \
645         for ((tmpelt) = NULL; (tmpelt) != MT_LIST_BUSY; ({                    \
646 					if (tmpelt) {                         \
647 					if (tmpelt2.prev)                     \
648 						MT_LIST_UNLOCK_ELT(tmpelt, tmpelt2);           \
649 					else                                  \
650 						_MT_LIST_UNLOCK_NEXT(tmpelt, tmpelt2.next); \
651 				} else                                        \
652 				_MT_LIST_RELINK_DELETED(tmpelt2);             \
653 				(tmpelt) = MT_LIST_BUSY;                      \
654 				}))                                           \
655 	for ((tmpelt) = (list_head), (tmpelt2).prev = NULL, (tmpelt2).next = _MT_LIST_LOCK_NEXT(tmpelt); ({ \
656 	              (item) = MT_LIST_ELEM((tmpelt2.next), typeof(item), member);  \
657 		      if (&item->member != (list_head)) {                     \
658 		                if (tmpelt2.prev != &item->member)            \
659 					tmpelt2.next = _MT_LIST_LOCK_NEXT(&item->member); \
660 				else \
661 					tmpelt2.next = tmpelt;                \
662 				if (tmpelt != NULL) {                         \
663 					if (tmpelt2.prev)                     \
664 						_MT_LIST_UNLOCK_PREV(tmpelt, tmpelt2.prev); \
665 					tmpelt2.prev = tmpelt;                \
666 				}                                             \
667 				(tmpelt) = &item->member;                     \
668 			}                                                     \
669 	    }),                                                               \
670 	     &item->member != (list_head);)
671 #endif /* _COMMON_MINI_CLIST_H */
672