From: Christopher Faulet Date: Thu, 16 Oct 2025 09:21:28 +0000 (+0200) Subject: WIP/MEDIUM: mt-list: Add more try-lock functions X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7a19fd00b97018a294f307f05871d2c617911e7f;p=thirdparty%2Fhaproxy.git WIP/MEDIUM: mt-list: Add more try-lock functions --- diff --git a/include/import/mt_list.h b/include/import/mt_list.h index b1eb7244f..ff5642ba6 100644 --- a/include/import/mt_list.h +++ b/include/import/mt_list.h @@ -771,6 +771,27 @@ static MT_INLINE struct mt_list mt_list_lock_next(struct mt_list *lh) return el; } +/* + * Same as mt_list_lock_next(), except it doesn't wait if the next + * is locked already, and just returns { NULL, NULL } + */ +static MT_INLINE struct mt_list mt_list_try_lock_next(struct mt_list *lh) +{ + struct mt_list el; + struct mt_list missed = { NULL, NULL }; + + el.next = __atomic_exchange_n(&lh->next, MT_LIST_BUSY, __ATOMIC_RELAXED); + if (el.next == MT_LIST_BUSY) + return missed; + + el.prev = __atomic_exchange_n(&el.next->prev, MT_LIST_BUSY, __ATOMIC_RELAXED); + if (el.prev == MT_LIST_BUSY) { + lh->next = el.next; + __atomic_thread_fence(__ATOMIC_RELEASE); + return missed; + } + return el; +} /* Opens the list just before which usually is the list's head, but not * necessarily. The link between and its prev element is cut and replaced @@ -861,6 +882,28 @@ static MT_INLINE struct mt_list mt_list_lock_elem(struct mt_list *el) return ret; } +/* + * Same as mt_list_lock_elem(), except it doesn't wait if the element + * is locked already, and just returns { NULL, NULL } + */ +static MT_INLINE struct mt_list mt_list_try_lock_elem(struct mt_list *el) +{ + struct mt_list ret; + struct mt_list missed = { NULL, NULL }; + + ret.next = __atomic_exchange_n(&el->next, MT_LIST_BUSY, __ATOMIC_RELAXED); + if (ret.next == MT_LIST_BUSY) + return missed; + + ret.prev = __atomic_exchange_n(&el->prev, MT_LIST_BUSY, __ATOMIC_RELAXED); + if (ret.prev == MT_LIST_BUSY) { + el->next = ret.next; + __atomic_thread_fence(__ATOMIC_RELEASE); + return missed; + } + return ret; +} + /* Restores element to its previous copy , effectively unlocking it. * This is to be used with the returned element from mt_list_lock_elem(). @@ -952,6 +995,51 @@ static MT_INLINE struct mt_list mt_list_lock_full(struct mt_list *el) return ret; } +/* + * Same as mt_list_lock_full(), except it doesn't wait if the element + * is locked already, and just returns { NULL, NULL } + */ +static MT_INLINE struct mt_list mt_list_try_lock_full(struct mt_list *el) +{ + struct mt_list *n2; + struct mt_list *p2; + struct mt_list ret; + struct mt_list missed = { NULL, NULL }; + + p2 = NULL; + ret.next = __atomic_exchange_n(&el->next, MT_LIST_BUSY, __ATOMIC_RELAXED); + if (ret.next == MT_LIST_BUSY) + return missed; + + ret.prev = __atomic_exchange_n(&el->prev, MT_LIST_BUSY, __ATOMIC_RELAXED); + if (ret.prev == MT_LIST_BUSY) { + el->next = ret.next; + __atomic_thread_fence(__ATOMIC_RELEASE); + return missed; + } + + if (ret.prev != el) { + p2 = __atomic_exchange_n(&ret.prev->next, MT_LIST_BUSY, __ATOMIC_RELAXED); + if (p2 == MT_LIST_BUSY) { + *el = ret; + __atomic_thread_fence(__ATOMIC_RELEASE); + return missed; + } + } + + if (ret.next != el) { + n2 = __atomic_exchange_n(&ret.next->prev, MT_LIST_BUSY, __ATOMIC_RELAXED); + if (n2 == MT_LIST_BUSY) { + if (p2 != NULL) + ret.prev->next = p2; + *el = ret; + __atomic_thread_fence(__ATOMIC_RELEASE); + return missed; + } + } + return ret; +} + /* Connects two ends in a list together, effectively unlocking the list if it * was locked. It takes a list head which contains a pointer to the prev and * next elements to connect together. It normally is a copy of a previous link