MINOR: list: add new macro MT_LIST_BEHEAD
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.
diff --git a/include/common/mini-clist.h b/include/common/mini-clist.h
index 9a81c9d..fdcc5c7 100644
--- a/include/common/mini-clist.h
+++ b/include/common/mini-clist.h
@@ -300,6 +300,47 @@
(_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).
*/