]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: list: add new macro MT_LIST_BEHEAD
authorWilly Tarreau <w@1wt.eu>
Fri, 4 Oct 2019 16:02:40 +0000 (18:02 +0200)
committerOlivier Houchard <cognet@ci0.org>
Fri, 11 Oct 2019 14:37:41 +0000 (16:37 +0200)
This macro atomically cuts the head of a list and returns the list
of elements as a detached list, meaning that they're all linked
together without any head. If the list was empty, NULL is returned.

include/common/mini-clist.h

index 9a81c9dd8a5b28f21707d4dbe0e239b69f26d18f..fdcc5c7553a1df68beb8fc5fe440354ba9de69f5 100644 (file)
@@ -300,6 +300,47 @@ struct cond_wordlist {
        (_ret);                                                            \
     })
 
+/*
+ * Detach a list from its head. A pointer to the first element is returned
+ * and the list is closed. If the list was empty, NULL is returned. This may
+ * exclusively be used with lists modified by MT_LIST_ADD/MT_LIST_ADDQ. This
+ * is incompatible with MT_LIST_DEL run concurrently.
+ */
+#define MT_LIST_BEHEAD(lh) ({                                       \
+       struct mt_list *_n;                                         \
+       struct mt_list *_p;                                         \
+       while (1) {                                                 \
+               _p = _HA_ATOMIC_XCHG(&(lh)->prev, MT_LIST_BUSY);    \
+               if (_p == MT_LIST_BUSY)                             \
+                       continue;                                   \
+               if (_p == (lh)) {                                   \
+                       (lh)->prev = _p;                            \
+                       _n = NULL;                                  \
+                       break;                                      \
+               }                                                   \
+               _n = _HA_ATOMIC_XCHG(&(lh)->next, MT_LIST_BUSY);    \
+               if (_n == MT_LIST_BUSY) {                           \
+                       (lh)->prev = _p;                            \
+                       __ha_barrier_store();                       \
+                       continue;                                   \
+               }                                                   \
+               if (_n == (lh)) {                                   \
+                       (lh)->next = _n;                            \
+                       (lh)->prev = _p;                            \
+                       _n = NULL;                                  \
+                       break;                                      \
+               }                                                   \
+               (lh)->next = (lh);                                  \
+               (lh)->prev = (lh);                                  \
+               _n->prev = _p;                                      \
+               _p->next = _n;                                      \
+               __ha_barrier_store();                               \
+               break;                                              \
+       }                                                           \
+       (_n);                                                       \
+})
+
+
 /* Remove an item from a list.
  * Returns 1 if we removed the item, 0 otherwise (because it was in no list).
  */