]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: mt_list: Implement MT_LIST_POP_LOCKED()
authorOlivier Houchard <ohouchard@haproxy.com>
Tue, 30 Sep 2025 12:39:01 +0000 (14:39 +0200)
committerOlivier Houchard <cognet@ci0.org>
Tue, 30 Sep 2025 14:25:07 +0000 (16:25 +0200)
Implement MT_LIST_POP_LOCKED(), that behaves as MT_LIST_POP() and
removes the first element from the list, if any, but keeps it locked.

This should be backported to 3.2, as it will be use in a bug fix in the
stick tables that affects 3.2 too.

doc/internals/api/mt_list.txt
include/import/mt_list.h

index 46d86eaf76dfc59f41fa689e5256c9ad0dc38996..734d0048cce1ab1080a42bc877ba935102bb1f3c 100644 (file)
@@ -245,6 +245,30 @@ mt_list_pop(l)
     #=========#
 
 
+mt_list_pop_locked(l)
+    Removes the list's first element, returns it locked. If the list was empty,
+    NULL is returned. A macro MT_LIST_POP_LOCKED() is provided for a
+    more convenient use; instead of returning the list element, it will return
+    the structure holding the element, taking care of preserving the NULL.
+
+  before:
+       +---+     +---+     +---+     +---+     +---+     +---+     +---+
+    #=>| L |<===>| A |<===>| B |<===>| C |<===>| D |<===>| E |<===>| F |<=#
+    #  +---+     +---+     +---+     +---+     +---+     +---+     +---+  #
+    #=====================================================================#
+
+  after:
+       +---+     +---+     +---+     +---+     +---+     +---+
+    #=>| L |<===>| B |<===>| C |<===>| D |<===>| E |<===>| F |<=#
+    #  +---+     +---+     +---+     +---+     +---+     +---+  #
+    #===========================================================#
+
+       +---+
+    # x| A |x #
+    #  +---+  #
+    #=========#
+
+
 _mt_list_lock_next(elt)
     Locks the link that starts at the next pointer of the designated element.
     The link is replaced by two locked pointers, and a pointer to the next
index 09526eb0b06930db7f24aa71b5880941b383fddc..8b27e53d97d8a68d129f7b91bf79da98f284b0be 100644 (file)
@@ -128,6 +128,19 @@ struct mt_list {
                (_n ? MT_LIST_ELEM(_n, t, m) : NULL);                   \
        })
 
+/* Returns a pointer of type <t> to the structure containing a member of type
+ * mt_list called <m> that comes from the first element in list <l>, that is
+ * atomically locked. If the list is empty, NULL is returned instead.
+ * Example:
+ *
+ *   while ((conn = MT_LIST_POP_LOCKED(queue, struct conn *, list))) ...
+ */
+#define MT_LIST_POP_LOCKED(lh, t, m)                                           \
+       ({                                                              \
+               struct mt_list *_n = mt_list_pop_locked(lh);            \
+               (_n ? MT_LIST_ELEM(_n, t, m) : NULL);                   \
+       })
+
 /* Iterates <item> through a list of items of type "typeof(*item)" which are
  * linked via a "struct mt_list" member named <member>. A pointer to the head
  * of the list is passed in <list_head>.
@@ -633,10 +646,10 @@ static MT_INLINE long mt_list_delete(struct mt_list *el)
 }
 
 
-/* Removes the first element from the list <lh>, and returns it in detached
+/* Removes the first element from the list <lh>, and returns it in locked
  * form. If the list is already empty, NULL is returned instead.
  */
-static MT_INLINE struct mt_list *mt_list_pop(struct mt_list *lh)
+static MT_INLINE struct mt_list *mt_list_pop_locked(struct mt_list *lh)
 {
        struct mt_list *n, *n2;
        struct mt_list *p, *p2;
@@ -687,15 +700,26 @@ static MT_INLINE struct mt_list *mt_list_pop(struct mt_list *lh)
                n2->prev = lh;
                __atomic_thread_fence(__ATOMIC_RELEASE);
 
-               n->prev = n->next = n;
-               __atomic_thread_fence(__ATOMIC_RELEASE);
-
                /* return n */
                break;
        }
        return n;
 }
 
+/* Removes the first element from the list <lh>, and returns it in detached
+ * form. If the list is already empty, NULL is returned instead.
+ */
+static MT_INLINE struct mt_list *mt_list_pop(struct mt_list *lh)
+{
+       struct mt_list *ret = mt_list_pop_locked(lh);
+
+       if (ret) {
+               ret->prev = ret->next = ret;
+               __atomic_thread_fence(__ATOMIC_RELEASE);
+       }
+       return ret;
+}
+
 
 /* Opens the list just after <lh> which usually is the list's head, but not
  * necessarily. The link between <lh> and its next element is cut and replaced