From d7f2bbcbe3900362670b243d648cbd33b602309b Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 4 Oct 2019 18:02:40 +0200 Subject: [PATCH] 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. --- include/common/mini-clist.h | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/include/common/mini-clist.h b/include/common/mini-clist.h index 9a81c9dd8a..fdcc5c7553 100644 --- a/include/common/mini-clist.h +++ b/include/common/mini-clist.h @@ -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). */