WIP/MEDIUM: mt-list: Add more try-lock functions

This commit is contained in:
Christopher Faulet 2025-10-16 11:21:28 +02:00
parent 53d8d28fdd
commit 7a19fd00b9

View File

@ -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