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