MINOR: mt_list: Implement MT_LIST_POP_LOCKED()

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.
This commit is contained in:
Olivier Houchard 2025-09-30 14:39:01 +02:00 committed by Olivier Houchard
parent 6316f958e3
commit cf26745857
2 changed files with 53 additions and 5 deletions

View 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) _mt_list_lock_next(elt)
Locks the link that starts at the next pointer of the designated element. 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 The link is replaced by two locked pointers, and a pointer to the next

View File

@ -128,6 +128,19 @@ struct mt_list {
(_n ? MT_LIST_ELEM(_n, t, m) : NULL); \ (_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 /* 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 * linked via a "struct mt_list" member named <member>. A pointer to the head
* of the list is passed in <list_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. * 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 *n, *n2;
struct mt_list *p, *p2; 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; n2->prev = lh;
__atomic_thread_fence(__ATOMIC_RELEASE); __atomic_thread_fence(__ATOMIC_RELEASE);
n->prev = n->next = n;
__atomic_thread_fence(__ATOMIC_RELEASE);
/* return n */ /* return n */
break; break;
} }
return n; 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 /* 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 * necessarily. The link between <lh> and its next element is cut and replaced