mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-12-02 16:21:27 +01:00
WIP/MEDIUM: mt-list: Add more try-lock functions
This commit is contained in:
parent
53d8d28fdd
commit
7a19fd00b9
@ -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 <lh> which usually is the list's head, but not
|
||||
* necessarily. The link between <lh> 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 <el> to its previous copy <back>, 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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user